Merge
diff --git a/make/data/jdwp/jdwp.spec b/make/data/jdwp/jdwp.spec
index 7ddbaf4..aadede2 100644
--- a/make/data/jdwp/jdwp.spec
+++ b/make/data/jdwp/jdwp.spec
@@ -1147,7 +1147,8 @@
(ErrorSet
(Error INVALID_CLASS "clazz is not the ID of a class.")
(Error INVALID_OBJECT "clazz is not a known ID.")
- (Error INVALID_METHODID "methodID is not the ID of a method.")
+ (Error INVALID_METHODID "methodID is not the ID of a static method in "
+ "this class type or one of its superclasses.")
(Error INVALID_THREAD)
(Error THREAD_NOT_SUSPENDED)
(Error VM_DEAD)
@@ -1250,6 +1251,83 @@
)
)
(CommandSet InterfaceType=5
+ (Command InvokeMethod=1
+ "Invokes a static method. "
+ "The method must not be a static initializer. "
+ "The method must be a member of the interface type. "
+ "<p>Since JDWP version 1.8 "
+ "<p>"
+ "The method invocation will occur in the specified thread. "
+ "Method invocation can occur only if the specified thread "
+ "has been suspended by an event. "
+ "Method invocation is not supported "
+ "when the target VM has been suspended by the front-end. "
+ "<p>"
+ "The specified method is invoked with the arguments in the specified "
+ "argument list. "
+ "The method invocation is synchronous; the reply packet is not "
+ "sent until the invoked method returns in the target VM. "
+ "The return value (possibly the void value) is "
+ "included in the reply packet. "
+ "If the invoked method throws an exception, the "
+ "exception object ID is set in the reply packet; otherwise, the "
+ "exception object ID is null. "
+ "<p>"
+ "For primitive arguments, the argument value's type must match the "
+ "argument's type exactly. For object arguments, there must exist a "
+ "widening reference conversion from the argument value's type to the "
+ "argument's type and the argument's type must be loaded. "
+ "<p>"
+ "By default, all threads in the target VM are resumed while "
+ "the method is being invoked if they were previously "
+ "suspended by an event or by a command. "
+ "This is done to prevent the deadlocks "
+ "that will occur if any of the threads own monitors "
+ "that will be needed by the invoked method. It is possible that "
+ "breakpoints or other events might occur during the invocation. "
+ "Note, however, that this implicit resume acts exactly like "
+ "the ThreadReference resume command, so if the thread's suspend "
+ "count is greater than 1, it will remain in a suspended state "
+ "during the invocation. By default, when the invocation completes, "
+ "all threads in the target VM are suspended, regardless their state "
+ "before the invocation. "
+ "<p>"
+ "The resumption of other threads during the invoke can be prevented "
+ "by specifying the INVOKE_SINGLE_THREADED "
+ "bit flag in the <code>options</code> field; however, "
+ "there is no protection against or recovery from the deadlocks "
+ "described above, so this option should be used with great caution. "
+ "Only the specified thread will be resumed (as described for all "
+ "threads above). Upon completion of a single threaded invoke, the invoking thread "
+ "will be suspended once again. Note that any threads started during "
+ "the single threaded invocation will not be suspended when the "
+ "invocation completes. "
+ "<p>"
+ "If the target VM is disconnected during the invoke (for example, through "
+ "the VirtualMachine dispose command) the method invocation continues. "
+ (Out
+ (interfaceType clazz "The interface type ID.")
+ (threadObject thread "The thread in which to invoke.")
+ (method methodID "The method to invoke.")
+ (Repeat arguments
+ (value arg "The argument value.")
+ )
+ (int options "Invocation <a href=\"#JDWP_InvokeOptions\">options</a>")
+ )
+ (Reply
+ (value returnValue "The returned value.")
+ (tagged-object exception "The thrown exception.")
+ )
+ (ErrorSet
+ (Error INVALID_CLASS "clazz is not the ID of an interface.")
+ (Error INVALID_OBJECT "clazz is not a known ID.")
+ (Error INVALID_METHODID "methodID is not the ID of a static method in this "
+ "interface type or is the ID of a static initializer.")
+ (Error INVALID_THREAD)
+ (Error THREAD_NOT_SUSPENDED)
+ (Error VM_DEAD)
+ )
+ )
)
(CommandSet Method=6
(Command LineTable=1
@@ -1543,7 +1621,7 @@
"<p>"
"By default, all threads in the target VM are resumed while "
"the method is being invoked if they were previously "
- "suspended by an event or by command. "
+ "suspended by an event or by a command. "
"This is done to prevent the deadlocks "
"that will occur if any of the threads own monitors "
"that will be needed by the invoked method. It is possible that "
@@ -1586,7 +1664,9 @@
(Error INVALID_OBJECT)
(Error INVALID_CLASS "clazz is not the ID of a reference "
"type.")
- (Error INVALID_METHODID "methodID is not the ID of a method.")
+ (Error INVALID_METHODID "methodID is not the ID of an instance method "
+ "in this object's type or one of its superclasses, "
+ "superinterfaces, or implemented interfaces.")
(Error INVALID_THREAD)
(Error THREAD_NOT_SUSPENDED)
(Error VM_DEAD)
diff --git a/src/share/back/InterfaceTypeImpl.c b/src/share/back/InterfaceTypeImpl.c
new file mode 100644
index 0000000..f25d353
--- /dev/null
+++ b/src/share/back/InterfaceTypeImpl.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "util.h"
+#include "InterfaceTypeImpl.h"
+#include "inStream.h"
+#include "outStream.h"
+
+static jboolean
+invokeStatic(PacketInputStream *in, PacketOutputStream *out)
+{
+ return sharedInvoke(in, out);
+}
+
+void *InterfaceType_Cmds[] = { (void *)0x1
+ , (void *)invokeStatic
+};
diff --git a/src/share/back/InterfaceTypeImpl.h b/src/share/back/InterfaceTypeImpl.h
new file mode 100644
index 0000000..ff29000
--- /dev/null
+++ b/src/share/back/InterfaceTypeImpl.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+extern void *InterfaceType_Cmds[];
diff --git a/src/share/back/VirtualMachineImpl.c b/src/share/back/VirtualMachineImpl.c
index 34c4a17..e856392 100644
--- a/src/share/back/VirtualMachineImpl.c
+++ b/src/share/back/VirtualMachineImpl.c
@@ -36,7 +36,7 @@
static char *versionName = "Java Debug Wire Protocol (Reference Implementation)";
static int majorVersion = 1; /* JDWP major version */
-static int minorVersion = 6; /* JDWP minor version */
+static int minorVersion = 8; /* JDWP minor version */
static jboolean
version(PacketInputStream *in, PacketOutputStream *out)
diff --git a/src/share/back/debugDispatch.c b/src/share/back/debugDispatch.c
index 1b1c782..e9e8c0e 100644
--- a/src/share/back/debugDispatch.c
+++ b/src/share/back/debugDispatch.c
@@ -29,6 +29,7 @@
#include "VirtualMachineImpl.h"
#include "ReferenceTypeImpl.h"
#include "ClassTypeImpl.h"
+#include "InterfaceTypeImpl.h"
#include "ArrayTypeImpl.h"
#include "FieldImpl.h"
#include "MethodImpl.h"
@@ -67,6 +68,7 @@
l1Array[JDWP_COMMAND_SET(VirtualMachine)] = (void *)VirtualMachine_Cmds;
l1Array[JDWP_COMMAND_SET(ReferenceType)] = (void *)ReferenceType_Cmds;
l1Array[JDWP_COMMAND_SET(ClassType)] = (void *)ClassType_Cmds;
+ l1Array[JDWP_COMMAND_SET(InterfaceType)] = (void *)InterfaceType_Cmds;
l1Array[JDWP_COMMAND_SET(ArrayType)] = (void *)ArrayType_Cmds;
l1Array[JDWP_COMMAND_SET(Field)] = (void *)Field_Cmds;
diff --git a/src/share/back/util.c b/src/share/back/util.c
index a043201..84f9b6e 100644
--- a/src/share/back/util.c
+++ b/src/share/back/util.c
@@ -591,6 +591,8 @@
invokeType = INVOKE_CONSTRUCTOR;
} else if (inStream_command(in) == JDWP_COMMAND(ClassType, InvokeMethod)) {
invokeType = INVOKE_STATIC;
+ } else if (inStream_command(in) == JDWP_COMMAND(InterfaceType, InvokeMethod)) {
+ invokeType = INVOKE_STATIC;
} else if (inStream_command(in) == JDWP_COMMAND(ObjectReference, InvokeMethod)) {
invokeType = INVOKE_INSTANCE;
} else {
diff --git a/src/share/classes/com/sun/jarsigner/ContentSigner.java b/src/share/classes/com/sun/jarsigner/ContentSigner.java
index 1a29bf7..0446ab4 100644
--- a/src/share/classes/com/sun/jarsigner/ContentSigner.java
+++ b/src/share/classes/com/sun/jarsigner/ContentSigner.java
@@ -37,6 +37,7 @@
* @author Vincent Ryan
*/
+@jdk.Exported
public abstract class ContentSigner {
/**
diff --git a/src/share/classes/com/sun/jarsigner/package-info.java b/src/share/classes/com/sun/jarsigner/package-info.java
new file mode 100644
index 0000000..554d4c7
--- /dev/null
+++ b/src/share/classes/com/sun/jarsigner/package-info.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/**
+ * This package comprises the interfaces and classes used to define the
+ * signing mechanism used by the <tt>jarsigner</tt> tool.
+ * <p>
+ * Clients may override the default signing mechanism of the <tt>jarsigner</tt>
+ * tool by supplying an alternative implementation of
+ * {@link com.sun.jarsigner.ContentSigner}.
+ */
+
+@jdk.Exported
+package com.sun.jarsigner;
diff --git a/src/share/classes/com/sun/jarsigner/package.html b/src/share/classes/com/sun/jarsigner/package.html
deleted file mode 100644
index b00d655..0000000
--- a/src/share/classes/com/sun/jarsigner/package.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<html>
-<!--
-
-Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
-DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-
-This code is free software; you can redistribute it and/or modify it
-under the terms of the GNU General Public License version 2 only, as
-published by the Free Software Foundation. Oracle designates this
-particular file as subject to the "Classpath" exception as provided
-by Oracle in the LICENSE file that accompanied this code.
-
-This code is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-version 2 for more details (a copy is included in the LICENSE file that
-accompanied this code).
-
-You should have received a copy of the GNU General Public License version
-2 along with this work; if not, write to the Free Software Foundation,
-Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-or visit www.oracle.com if you need additional information or have any
-questions.
--->
- <head>
- <title>Jarsigner Signing Mechanism Package</title>
- </head>
- <body>
-This package comprises the interfaces and classes used to define the
-signing mechanism used by the <tt>jarsigner</tt> tool.
-<p>
-Clients may override the default signing mechanism of the <tt>jarsigner</tt>
-tool by supplying an alternative implementation of
-{@link com.sun.jarsigner.ContentSigner}.
- </body>
-</html>
diff --git a/src/share/classes/com/sun/java/util/jar/pack/DriverResource_ja.java b/src/share/classes/com/sun/java/util/jar/pack/DriverResource_ja.java
index f22c34a..022b2be 100644
--- a/src/share/classes/com/sun/java/util/jar/pack/DriverResource_ja.java
+++ b/src/share/classes/com/sun/java/util/jar/pack/DriverResource_ja.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -84,7 +84,7 @@
" -V\u3001--version \u30D7\u30ED\u30B0\u30E9\u30E0\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u3092\u51FA\u529B\u3057\u307E\u3059",
" -J{X} \u30AA\u30D7\u30B7\u30E7\u30F3X\u3092\u57FA\u790E\u3068\u306A\u308BJava VM\u306B\u6E21\u3057\u307E\u3059",
"",
- "\u6CE8\u610F:",
+ "\u6CE8:",
" -P\u3001-C\u3001-F\u3001-M\u304A\u3088\u3073-D\u30AA\u30D7\u30B7\u30E7\u30F3\u306F\u7D2F\u7A4D\u3055\u308C\u307E\u3059\u3002",
" \u5C5E\u6027\u5B9A\u7FA9\u306E\u4F8B: -C SourceFile=RUH .",
" Config.\u30D5\u30A1\u30A4\u30EB\u30FB\u30D7\u30ED\u30D1\u30C6\u30A3\u306F\u3001Pack200 API\u306B\u3088\u3063\u3066\u5B9A\u7FA9\u3055\u308C\u307E\u3059\u3002",
diff --git a/src/share/classes/com/sun/jdi/ClassType.java b/src/share/classes/com/sun/jdi/ClassType.java
index 919f3ab..296f2e7 100644
--- a/src/share/classes/com/sun/jdi/ClassType.java
+++ b/src/share/classes/com/sun/jdi/ClassType.java
@@ -103,7 +103,7 @@
* <p>
* Object values must be assignment compatible with the field type
* (This implies that the field type must be loaded through the
- * enclosing class's class loader). Primitive values must be
+ * enclosing class' class loader). Primitive values must be
* either assignment compatible with the field type or must be
* convertible to the field type without loss of information.
* See JLS section 5.2 for more information on assignment
@@ -153,7 +153,7 @@
* <p>
* Object arguments must be assignment compatible with the argument type
* (This implies that the argument type must be loaded through the
- * enclosing class's class loader). Primitive arguments must be
+ * enclosing class' class loader). Primitive arguments must be
* either assignment compatible with the argument type or must be
* convertible to the argument type without loss of information.
* If the method being called accepts a variable number of arguments,
@@ -216,7 +216,7 @@
* @return a {@link Value} mirror of the invoked method's return value.
* @throws java.lang.IllegalArgumentException if the method is not
* a member of this class or a superclass, if the size of the argument list
- * does not match the number of declared arguemnts for the method, or
+ * does not match the number of declared arguments for the method, or
* if the method is an initializer, constructor or static intializer.
* @throws {@link InvalidTypeException} if any argument in the
* argument list is not assignable to the corresponding method argument
@@ -230,7 +230,7 @@
* @throws InvalidTypeException If the arguments do not meet this requirement --
* Object arguments must be assignment compatible with the argument
* type. This implies that the argument type must be
- * loaded through the enclosing class's class loader.
+ * loaded through the enclosing class' class loader.
* Primitive arguments must be either assignment compatible with the
* argument type or must be convertible to the argument type without loss
* of information. See JLS section 5.2 for more information on assignment
@@ -267,7 +267,7 @@
* <p>
* Object arguments must be assignment compatible with the argument type
* (This implies that the argument type must be loaded through the
- * enclosing class's class loader). Primitive arguments must be
+ * enclosing class' class loader). Primitive arguments must be
* either assignment compatible with the argument type or must be
* convertible to the argument type without loss of information.
* If the method being called accepts a variable number of arguments,
@@ -335,7 +335,7 @@
* @throws InvalidTypeException If the arguments do not meet this requirement --
* Object arguments must be assignment compatible with the argument
* type. This implies that the argument type must be
- * loaded through the enclosing class's class loader.
+ * loaded through the enclosing class' class loader.
* Primitive arguments must be either assignment compatible with the
* argument type or must be convertible to the argument type without loss
* of information. See JLS section 5.2 for more information on assignment
diff --git a/src/share/classes/com/sun/jdi/InterfaceType.java b/src/share/classes/com/sun/jdi/InterfaceType.java
index 3b2790a..9436e48 100644
--- a/src/share/classes/com/sun/jdi/InterfaceType.java
+++ b/src/share/classes/com/sun/jdi/InterfaceType.java
@@ -79,4 +79,123 @@
* If none exist, returns a zero length List.
*/
List<ClassType> implementors();
+
+ /**
+ * Invokes the specified static {@link Method} in the
+ * target VM. The
+ * specified method must be defined in this interface.
+ * The method must be a static method
+ * but not a static initializer.
+ * <p>
+ * The method invocation will occur in the specified thread.
+ * Method invocation can occur only if the specified thread
+ * has been suspended by an event which occurred in that thread.
+ * Method invocation is not supported
+ * when the target VM has been suspended through
+ * {@link VirtualMachine#suspend} or when the specified thread
+ * is suspended through {@link ThreadReference#suspend}.
+ * <p>
+ * The specified method is invoked with the arguments in the specified
+ * argument list. The method invocation is synchronous; this method
+ * does not return until the invoked method returns in the target VM.
+ * If the invoked method throws an exception, this method will throw
+ * an {@link InvocationException} which contains a mirror to the exception
+ * object thrown.
+ * <p>
+ * Object arguments must be assignment compatible with the argument type
+ * (This implies that the argument type must be loaded through the
+ * enclosing class' class loader). Primitive arguments must be
+ * either assignment compatible with the argument type or must be
+ * convertible to the argument type without loss of information.
+ * If the method being called accepts a variable number of arguments,
+ * then the last argument type is an array of some component type.
+ * The argument in the matching position can be omitted, or can be null,
+ * an array of the same component type, or an argument of the
+ * component type followed by any number of other arguments of the same
+ * type. If the argument is omitted, then a 0 length array of the
+ * component type is passed. The component type can be a primitive type.
+ * Autoboxing is not supported.
+ *
+ * See Section 5.2 of
+ * <cite>The Java™ Language Specification</cite>
+ * for more information on assignment compatibility.
+ * <p>
+ * By default, all threads in the target VM are resumed while
+ * the method is being invoked if they were previously
+ * suspended by an event or by {@link VirtualMachine#suspend} or
+ * {@link ThreadReference#suspend}. This is done to prevent the deadlocks
+ * that will occur if any of the threads own monitors
+ * that will be needed by the invoked method.
+ * Note, however, that this implicit resume acts exactly like
+ * {@link ThreadReference#resume}, so if the thread's suspend
+ * count is greater than 1, it will remain in a suspended state
+ * during the invocation and thus a deadlock could still occur.
+ * By default, when the invocation completes,
+ * all threads in the target VM are suspended, regardless their state
+ * before the invocation.
+ * It is possible that
+ * breakpoints or other events might occur during the invocation.
+ * This can cause deadlocks as described above. It can also cause a deadlock
+ * if invokeMethod is called from the client's event handler thread. In this
+ * case, this thread will be waiting for the invokeMethod to complete and
+ * won't read the EventSet that comes in for the new event. If this
+ * new EventSet is SUSPEND_ALL, then a deadlock will occur because no
+ * one will resume the EventSet. To avoid this, all EventRequests should
+ * be disabled before doing the invokeMethod, or the invokeMethod should
+ * not be done from the client's event handler thread.
+ * <p>
+ * The resumption of other threads during the invocation can be prevented
+ * by specifying the {@link #INVOKE_SINGLE_THREADED}
+ * bit flag in the <code>options</code> argument; however,
+ * there is no protection against or recovery from the deadlocks
+ * described above, so this option should be used with great caution.
+ * Only the specified thread will be resumed (as described for all
+ * threads above). Upon completion of a single threaded invoke, the invoking thread
+ * will be suspended once again. Note that any threads started during
+ * the single threaded invocation will not be suspended when the
+ * invocation completes.
+ * <p>
+ * If the target VM is disconnected during the invoke (for example, through
+ * {@link VirtualMachine#dispose}) the method invocation continues.
+ *
+ * @param thread the thread in which to invoke.
+ * @param method the {@link Method} to invoke.
+ * @param arguments the list of {@link Value} arguments bound to the
+ * invoked method. Values from the list are assigned to arguments
+ * in the order they appear in the method signature.
+ * @param options the integer bit flag options.
+ * @return a {@link Value} mirror of the invoked method's return value.
+ * @throws java.lang.IllegalArgumentException if the method is not
+ * a member of this interface, if the size of the argument list
+ * does not match the number of declared arguments for the method, or
+ * if the method is not static or is a static initializer.
+ * @throws {@link InvalidTypeException} if any argument in the
+ * argument list is not assignable to the corresponding method argument
+ * type.
+ * @throws ClassNotLoadedException if any argument type has not yet been loaded
+ * through the appropriate class loader.
+ * @throws IncompatibleThreadStateException if the specified thread has not
+ * been suspended by an event.
+ * @throws InvocationException if the method invocation resulted in
+ * an exception in the target VM.
+ * @throws InvalidTypeException If the arguments do not meet this requirement --
+ * Object arguments must be assignment compatible with the argument
+ * type. This implies that the argument type must be
+ * loaded through the enclosing class' class loader.
+ * Primitive arguments must be either assignment compatible with the
+ * argument type or must be convertible to the argument type without loss
+ * of information. See JLS section 5.2 for more information on assignment
+ * compatibility.
+ * @throws VMCannotBeModifiedException if the VirtualMachine is read-only - see {@link VirtualMachine#canBeModified()}.
+ *
+ * @since 1.8
+ */
+ default Value invokeMethod(ThreadReference thread, Method method,
+ List<? extends Value> arguments, int options)
+ throws InvalidTypeException,
+ ClassNotLoadedException,
+ IncompatibleThreadStateException,
+ InvocationException {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/src/share/classes/com/sun/jdi/Method.java b/src/share/classes/com/sun/jdi/Method.java
index 19b13e0..eb81b05 100644
--- a/src/share/classes/com/sun/jdi/Method.java
+++ b/src/share/classes/com/sun/jdi/Method.java
@@ -138,6 +138,18 @@
boolean isAbstract();
/**
+ * Determine if this method is a default method
+ *
+ * @return <code>true</code> if the method is declared default;
+ * false otherwise
+ *
+ * @since 1.8
+ */
+ default boolean isDefault() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Determine if this method is synchronized.
*
* @return <code>true</code> if the method is declared synchronized;
diff --git a/src/share/classes/com/sun/jdi/ObjectReference.java b/src/share/classes/com/sun/jdi/ObjectReference.java
index 797d5ad..b6bf5a3 100644
--- a/src/share/classes/com/sun/jdi/ObjectReference.java
+++ b/src/share/classes/com/sun/jdi/ObjectReference.java
@@ -194,10 +194,10 @@
* {@link #INVOKE_NONVIRTUAL} bit flag in the <code>options</code>
* argument. If this flag is set, the specified method is invoked
* whether or not it is overridden for this object's runtime type.
- * The method, in this case, must not belong to an interface and
- * must not be abstract. This option is useful for performing method
- * invocations like those done with the <code>super</code> keyword in
- * the Java programming language.
+ * The method, in this case, must have an implementation, either in a class
+ * or an interface. This option is useful for performing method invocations
+ * like those done with the <code>super</code> keyword in the Java programming
+ * language.
* <p>
* By default, all threads in the target VM are resumed while
* the method is being invoked if they were previously
@@ -246,10 +246,10 @@
* @return a {@link Value} mirror of the invoked method's return value.
* @throws java.lang.IllegalArgumentException if the method is not
* a member of this object's class, if the size of the argument list
- * does not match the number of declared arguemnts for the method,
+ * does not match the number of declared arguments for the method,
* if the method is a constructor or static intializer, or
* if {@link #INVOKE_NONVIRTUAL} is specified and the method is
- * either abstract or an interface member.
+ * either abstract or a non-default interface member.
* @throws {@link InvalidTypeException} if any argument in the
* argument list is not assignable to the corresponding method argument
* type.
diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties
index cf95074..c5314fa 100644
--- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties
+++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties
@@ -42,13 +42,13 @@
FileChooser.renameErrorFileExists.textAndMnemonic={0}\u306E\u540D\u524D\u3092\u5909\u66F4\u3067\u304D\u307E\u305B\u3093: \u6307\u5B9A\u3057\u305F\u540D\u524D\u306E\u30D5\u30A1\u30A4\u30EB\u306F\u3059\u3067\u306B\u5B58\u5728\u3057\u307E\u3059\u3002\u5225\u306E\u30D5\u30A1\u30A4\u30EB\u540D\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002
FileChooser.acceptAllFileFilter.textAndMnemonic=\u3059\u3079\u3066\u306E\u30D5\u30A1\u30A4\u30EB
FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88
-FileChooser.saveButton.textAndMnemonic=\u4FDD\u5B58
-FileChooser.openButton.textAndMnemonic=\u958B\u304F
+FileChooser.saveButton.textAndMnemonic=\u4FDD\u5B58(&S)
+FileChooser.openButton.textAndMnemonic=\u958B\u304F(&O)
FileChooser.saveDialogTitle.textAndMnemonic=\u4FDD\u5B58
FileChooser.openDialogTitle.textAndMnemonic=\u958B\u304F
FileChooser.updateButton.textAndMnemonic=\u66F4\u65B0(&U)
FileChooser.helpButton.textAndMnemonic=\u30D8\u30EB\u30D7(&H)
-FileChooser.directoryOpenButton.textAndMnemonic=\u958B\u304F
+FileChooser.directoryOpenButton.textAndMnemonic=\u958B\u304F(&O)
# File Size Units
FileChooser.fileSizeKiloBytes={0} KB
diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties
index c8e67df..7f31303 100644
--- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties
+++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties
@@ -42,13 +42,13 @@
FileChooser.renameErrorFileExists.textAndMnemonic={0}\uC758 \uC774\uB984\uC744 \uBC14\uAFC0 \uC218 \uC5C6\uC74C: \uC9C0\uC815\uD55C \uC774\uB984\uC744 \uC0AC\uC6A9\uD558\uB294 \uD30C\uC77C\uC774 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uB2E4\uB978 \uD30C\uC77C \uC774\uB984\uC744 \uC9C0\uC815\uD558\uC2ED\uC2DC\uC624.
FileChooser.acceptAllFileFilter.textAndMnemonic=\uBAA8\uB4E0 \uD30C\uC77C
FileChooser.cancelButton.textAndMnemonic=\uCDE8\uC18C
-FileChooser.saveButton.textAndMnemonic=\uC800\uC7A5
-FileChooser.openButton.textAndMnemonic=\uC5F4\uAE30
+FileChooser.saveButton.textAndMnemonic=\uC800\uC7A5(&S)
+FileChooser.openButton.textAndMnemonic=\uC5F4\uAE30(&O)
FileChooser.saveDialogTitle.textAndMnemonic=\uC800\uC7A5
FileChooser.openDialogTitle.textAndMnemonic=\uC5F4\uAE30
FileChooser.updateButton.textAndMnemonic=\uC5C5\uB370\uC774\uD2B8(&U)
FileChooser.helpButton.textAndMnemonic=\uB3C4\uC6C0\uB9D0(&H)
-FileChooser.directoryOpenButton.textAndMnemonic=\uC5F4\uAE30
+FileChooser.directoryOpenButton.textAndMnemonic=\uC5F4\uAE30(&O)
# File Size Units
FileChooser.fileSizeKiloBytes={0} KB
diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties
index ab3bb26..d4c3572 100644
--- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties
+++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties
@@ -42,13 +42,13 @@
FileChooser.renameErrorFileExists.textAndMnemonic=\u65E0\u6CD5\u91CD\u547D\u540D{0}: \u5DF2\u5B58\u5728\u5177\u6709\u6240\u6307\u5B9A\u540D\u79F0\u7684\u6587\u4EF6\u3002\u8BF7\u6307\u5B9A\u5176\u4ED6\u6587\u4EF6\u540D\u3002
FileChooser.acceptAllFileFilter.textAndMnemonic=\u6240\u6709\u6587\u4EF6
FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88
-FileChooser.saveButton.textAndMnemonic=\u4FDD\u5B58
-FileChooser.openButton.textAndMnemonic=\u6253\u5F00
+FileChooser.saveButton.textAndMnemonic=\u4FDD\u5B58(&S)
+FileChooser.openButton.textAndMnemonic=\u6253\u5F00(&O)
FileChooser.saveDialogTitle.textAndMnemonic=\u4FDD\u5B58
FileChooser.openDialogTitle.textAndMnemonic=\u6253\u5F00
FileChooser.updateButton.textAndMnemonic=\u66F4\u65B0(&U)
FileChooser.helpButton.textAndMnemonic=\u5E2E\u52A9(&H)
-FileChooser.directoryOpenButton.textAndMnemonic=\u6253\u5F00
+FileChooser.directoryOpenButton.textAndMnemonic=\u6253\u5F00(&O)
# File Size Units
FileChooser.fileSizeKiloBytes={0} KB
diff --git a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties
index d4b4795..6541661 100644
--- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties
+++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties
@@ -42,13 +42,13 @@
FileChooser.renameErrorFileExists.textAndMnemonic=\u7121\u6CD5\u91CD\u65B0\u547D\u540D {0}: \u5DF2\u7D93\u5B58\u5728\u60A8\u6240\u6307\u5B9A\u540D\u7A31\u7684\u6A94\u6848\u3002\u8ACB\u6307\u5B9A\u4E0D\u540C\u7684\u540D\u7A31\u3002
FileChooser.acceptAllFileFilter.textAndMnemonic=\u6240\u6709\u6A94\u6848
FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88
-FileChooser.saveButton.textAndMnemonic=\u5132\u5B58
-FileChooser.openButton.textAndMnemonic=\u958B\u555F
+FileChooser.saveButton.textAndMnemonic=\u5132\u5B58(&S)
+FileChooser.openButton.textAndMnemonic=\u958B\u555F(&O)
FileChooser.saveDialogTitle.textAndMnemonic=\u5132\u5B58
FileChooser.openDialogTitle.textAndMnemonic=\u958B\u555F
FileChooser.updateButton.textAndMnemonic=\u66F4\u65B0(&U)
FileChooser.helpButton.textAndMnemonic=\u8AAA\u660E(&H)
-FileChooser.directoryOpenButton.textAndMnemonic=\u958B\u555F
+FileChooser.directoryOpenButton.textAndMnemonic=\u958B\u555F(&O)
# File Size Units
FileChooser.fileSizeKiloBytes={0} KB
diff --git a/src/share/classes/com/sun/tools/example/debug/expr/LValue.java b/src/share/classes/com/sun/tools/example/debug/expr/LValue.java
index 97794c5..1737137 100644
--- a/src/share/classes/com/sun/tools/example/debug/expr/LValue.java
+++ b/src/share/classes/com/sun/tools/example/debug/expr/LValue.java
@@ -559,6 +559,9 @@
} else if (refType instanceof ClassType) {
ClassType clazz = (ClassType)refType;
return jdiValue = clazz.invokeMethod(thread, matchingMethod, methodArguments, 0);
+ } else if (refType instanceof InterfaceType) {
+ InterfaceType iface = (InterfaceType)refType;
+ return jdiValue = iface.invokeMethod(thread, matchingMethod, methodArguments, 0);
} else {
throw new InvalidTypeException("Cannot invoke static method on " +
refType.name());
diff --git a/src/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java b/src/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java
index 4116c5e..0c83e4d 100644
--- a/src/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java
+++ b/src/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java
@@ -31,6 +31,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
+import java.util.Set;
public class ArrayTypeImpl extends ReferenceTypeImpl
implements ArrayType
@@ -61,7 +62,8 @@
return findType(componentSignature());
}
- void addVisibleMethods(Map<String, Method> map) {
+ @Override
+ void addVisibleMethods(Map<String, Method> map, Set<InterfaceType> seenInterfaces) {
// arrays don't have methods
}
diff --git a/src/share/classes/com/sun/tools/jdi/ClassTypeImpl.java b/src/share/classes/com/sun/tools/jdi/ClassTypeImpl.java
index 2b2c0ee..b815d1a 100644
--- a/src/share/classes/com/sun/tools/jdi/ClassTypeImpl.java
+++ b/src/share/classes/com/sun/tools/jdi/ClassTypeImpl.java
@@ -29,9 +29,27 @@
import java.util.*;
-public class ClassTypeImpl extends ReferenceTypeImpl
+final public class ClassTypeImpl extends InvokableTypeImpl
implements ClassType
{
+ private static class IResult implements InvocationResult {
+ final private JDWP.ClassType.InvokeMethod rslt;
+
+ public IResult(JDWP.ClassType.InvokeMethod rslt) {
+ this.rslt = rslt;
+ }
+
+ @Override
+ public ObjectReferenceImpl getException() {
+ return rslt.exception;
+ }
+
+ @Override
+ public ValueImpl getResult() {
+ return rslt.returnValue;
+ }
+ }
+
private boolean cachedSuperclass = false;
private ClassType superclass = null;
private int lastLine = -1;
@@ -65,6 +83,7 @@
return superclass;
}
+ @Override
public List<InterfaceType> interfaces() {
if (interfaces == null) {
interfaces = getInterfaces();
@@ -72,26 +91,9 @@
return interfaces;
}
- void addInterfaces(List<InterfaceType> list) {
- List<InterfaceType> immediate = interfaces();
- list.addAll(interfaces());
-
- Iterator<InterfaceType> iter = immediate.iterator();
- while (iter.hasNext()) {
- InterfaceTypeImpl interfaze = (InterfaceTypeImpl)iter.next();
- interfaze.addSuperinterfaces(list);
- }
-
- ClassTypeImpl superclass = (ClassTypeImpl)superclass();
- if (superclass != null) {
- superclass.addInterfaces(list);
- }
- }
-
- public List<InterfaceType> allInterfaces() {
- List<InterfaceType> all = new ArrayList<InterfaceType>();
- addInterfaces(all);
- return all;
+ @Override
+ public List<InterfaceType> allInterfaces() {
+ return getAllInterfaces();
}
public List<ClassType> subclasses() {
@@ -159,28 +161,6 @@
}
}
- PacketStream sendInvokeCommand(final ThreadReferenceImpl thread,
- final MethodImpl method,
- final ValueImpl[] args,
- final int options) {
- CommandSender sender =
- new CommandSender() {
- public PacketStream send() {
- return JDWP.ClassType.InvokeMethod.enqueueCommand(
- vm, ClassTypeImpl.this, thread,
- method.ref(), args, options);
- }
- };
-
- PacketStream stream;
- if ((options & INVOKE_SINGLE_THREADED) != 0) {
- stream = thread.sendResumingCommand(sender);
- } else {
- stream = vm.sendResumingCommand(sender);
- }
- return stream;
- }
-
PacketStream sendNewInstanceCommand(final ThreadReferenceImpl thread,
final MethodImpl method,
final ValueImpl[] args,
@@ -203,52 +183,6 @@
return stream;
}
- public Value invokeMethod(ThreadReference threadIntf, Method methodIntf,
- List<? extends Value> origArguments, int options)
- throws InvalidTypeException,
- ClassNotLoadedException,
- IncompatibleThreadStateException,
- InvocationException {
- validateMirror(threadIntf);
- validateMirror(methodIntf);
- validateMirrorsOrNulls(origArguments);
-
- MethodImpl method = (MethodImpl)methodIntf;
- ThreadReferenceImpl thread = (ThreadReferenceImpl)threadIntf;
-
- validateMethodInvocation(method);
-
- List<? extends Value> arguments = method.validateAndPrepareArgumentsForInvoke(origArguments);
-
- ValueImpl[] args = arguments.toArray(new ValueImpl[0]);
- JDWP.ClassType.InvokeMethod ret;
- try {
- PacketStream stream =
- sendInvokeCommand(thread, method, args, options);
- ret = JDWP.ClassType.InvokeMethod.waitForReply(vm, stream);
- } catch (JDWPException exc) {
- if (exc.errorCode() == JDWP.Error.INVALID_THREAD) {
- throw new IncompatibleThreadStateException();
- } else {
- throw exc.toJDIException();
- }
- }
-
- /*
- * There is an implict VM-wide suspend at the conclusion
- * of a normal (non-single-threaded) method invoke
- */
- if ((options & INVOKE_SINGLE_THREADED) == 0) {
- vm.notifySuspend();
- }
-
- if (ret.exception != null) {
- throw new InvocationException(ret.exception);
- } else {
- return ret.returnValue;
- }
- }
-
public ObjectReference newInstance(ThreadReference threadIntf,
Method methodIntf,
List<? extends Value> origArguments,
@@ -311,58 +245,6 @@
return method;
}
- public List<Method> allMethods() {
- ArrayList<Method> list = new ArrayList<Method>(methods());
-
- ClassType clazz = superclass();
- while (clazz != null) {
- list.addAll(clazz.methods());
- clazz = clazz.superclass();
- }
-
- /*
- * Avoid duplicate checking on each method by iterating through
- * duplicate-free allInterfaces() rather than recursing
- */
- for (InterfaceType interfaze : allInterfaces()) {
- list.addAll(interfaze.methods());
- }
-
- return list;
- }
-
- List<ReferenceType> inheritedTypes() {
- List<ReferenceType> inherited = new ArrayList<ReferenceType>();
- if (superclass() != null) {
- inherited.add(0, (ReferenceType)superclass()); /* insert at front */
- }
- for (ReferenceType rt : interfaces()) {
- inherited.add(rt);
- }
- return inherited;
- }
-
- void validateMethodInvocation(Method method)
- throws InvalidTypeException,
- InvocationException {
- /*
- * Method must be in this class or a superclass.
- */
- ReferenceTypeImpl declType = (ReferenceTypeImpl)method.declaringType();
- if (!declType.isAssignableFrom(this)) {
- throw new IllegalArgumentException("Invalid method");
- }
-
- /*
- * Method must be a static and not a static initializer
- */
- if (!method.isStatic()) {
- throw new IllegalArgumentException("Cannot invoke instance method on a class type");
- } else if (method.isStaticInitializer()) {
- throw new IllegalArgumentException("Cannot invoke static initializer");
- }
- }
-
void validateConstructorInvocation(Method method)
throws InvalidTypeException,
InvocationException {
@@ -382,47 +264,33 @@
}
}
- void addVisibleMethods(Map<String, Method> methodMap) {
- /*
- * Add methods from
- * parent types first, so that the methods in this class will
- * overwrite them in the hash table
- */
-
- Iterator<InterfaceType> iter = interfaces().iterator();
- while (iter.hasNext()) {
- InterfaceTypeImpl interfaze = (InterfaceTypeImpl)iter.next();
- interfaze.addVisibleMethods(methodMap);
- }
-
- ClassTypeImpl clazz = (ClassTypeImpl)superclass();
- if (clazz != null) {
- clazz.addVisibleMethods(methodMap);
- }
-
- addToMethodMap(methodMap, methods());
- }
-
- boolean isAssignableTo(ReferenceType type) {
- ClassTypeImpl superclazz = (ClassTypeImpl)superclass();
- if (this.equals(type)) {
- return true;
- } else if ((superclazz != null) && superclazz.isAssignableTo(type)) {
- return true;
- } else {
- List<InterfaceType> interfaces = interfaces();
- Iterator<InterfaceType> iter = interfaces.iterator();
- while (iter.hasNext()) {
- InterfaceTypeImpl interfaze = (InterfaceTypeImpl)iter.next();
- if (interfaze.isAssignableTo(type)) {
- return true;
- }
- }
- return false;
- }
- }
public String toString() {
return "class " + name() + " (" + loaderString() + ")";
}
+
+ @Override
+ CommandSender getInvokeMethodSender(ThreadReferenceImpl thread,
+ MethodImpl method,
+ ValueImpl[] args,
+ int options) {
+ return () ->
+ JDWP.ClassType.InvokeMethod.enqueueCommand(vm,
+ ClassTypeImpl.this,
+ thread,
+ method.ref(),
+ args,
+ options);
+ }
+
+ @Override
+ InvocationResult waitForReply(PacketStream stream) throws JDWPException {
+ return new IResult(JDWP.ClassType.InvokeMethod.waitForReply(vm, stream));
+ }
+
+ @Override
+ boolean canInvoke(Method method) {
+ // Method must be in this class or a superclass.
+ return ((ReferenceTypeImpl)method.declaringType()).isAssignableFrom(this);
+ }
}
diff --git a/src/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java b/src/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java
index 8fa7670..da7e55a 100644
--- a/src/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java
+++ b/src/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java
@@ -29,13 +29,31 @@
import java.util.List;
import java.util.ArrayList;
-import java.util.Map;
-import java.util.Iterator;
import java.util.Collections;
+import java.util.Set;
import java.lang.ref.SoftReference;
-public class InterfaceTypeImpl extends ReferenceTypeImpl
- implements InterfaceType {
+final public class InterfaceTypeImpl extends InvokableTypeImpl
+ implements InterfaceType {
+
+ private static class IResult implements InvocationResult {
+ final private JDWP.InterfaceType.InvokeMethod rslt;
+
+ public IResult(JDWP.InterfaceType.InvokeMethod rslt) {
+ this.rslt = rslt;
+ }
+
+ @Override
+ public ObjectReferenceImpl getException() {
+ return rslt.exception;
+ }
+
+ @Override
+ public ValueImpl getResult() {
+ return rslt.returnValue;
+ }
+
+ }
private SoftReference<List<InterfaceType>> superinterfacesRef = null;
@@ -80,98 +98,6 @@
return implementors;
}
- void addVisibleMethods(Map<String, Method> methodMap) {
- /*
- * Add methods from
- * parent types first, so that the methods in this class will
- * overwrite them in the hash table
- */
-
- for (InterfaceType interfaze : superinterfaces()) {
- ((InterfaceTypeImpl)interfaze).addVisibleMethods(methodMap);
- }
-
- addToMethodMap(methodMap, methods());
- }
-
- public List<Method> allMethods() {
- ArrayList<Method> list = new ArrayList<Method>(methods());
-
- /*
- * It's more efficient if don't do this
- * recursively.
- */
- for (InterfaceType interfaze : allSuperinterfaces()) {
- list.addAll(interfaze.methods());
- }
-
- return list;
- }
-
- List<InterfaceType> allSuperinterfaces() {
- ArrayList<InterfaceType> list = new ArrayList<InterfaceType>();
- addSuperinterfaces(list);
- return list;
- }
-
- void addSuperinterfaces(List<InterfaceType> list) {
- /*
- * This code is a little strange because it
- * builds the list with a more suitable order than the
- * depth-first approach a normal recursive solution would
- * take. Instead, all direct superinterfaces precede all
- * indirect ones.
- */
-
- /*
- * Get a list of direct superinterfaces that's not already in the
- * list being built.
- */
- List<InterfaceType> immediate = new ArrayList<InterfaceType>(superinterfaces());
- Iterator<InterfaceType> iter = immediate.iterator();
- while (iter.hasNext()) {
- InterfaceType interfaze = iter.next();
- if (list.contains(interfaze)) {
- iter.remove();
- }
- }
-
- /*
- * Add all new direct superinterfaces
- */
- list.addAll(immediate);
-
- /*
- * Recurse for all new direct superinterfaces.
- */
- iter = immediate.iterator();
- while (iter.hasNext()) {
- InterfaceTypeImpl interfaze = (InterfaceTypeImpl)iter.next();
- interfaze.addSuperinterfaces(list);
- }
- }
-
- boolean isAssignableTo(ReferenceType type) {
-
- // Exact match?
- if (this.equals(type)) {
- return true;
- } else {
- // Try superinterfaces.
- for (InterfaceType interfaze : superinterfaces()) {
- if (((InterfaceTypeImpl)interfaze).isAssignableTo(type)) {
- return true;
- }
- }
-
- return false;
- }
- }
-
- List<InterfaceType> inheritedTypes() {
- return superinterfaces();
- }
-
public boolean isInitialized() {
return isPrepared();
}
@@ -179,4 +105,39 @@
public String toString() {
return "interface " + name() + " (" + loaderString() + ")";
}
-}
+
+ @Override
+ InvocationResult waitForReply(PacketStream stream) throws JDWPException {
+ return new IResult(JDWP.InterfaceType.InvokeMethod.waitForReply(vm, stream));
+ }
+
+ @Override
+ CommandSender getInvokeMethodSender(final ThreadReferenceImpl thread,
+ final MethodImpl method,
+ final ValueImpl[] args,
+ final int options) {
+ return () ->
+ JDWP.InterfaceType.InvokeMethod.enqueueCommand(vm,
+ InterfaceTypeImpl.this,
+ thread,
+ method.ref(),
+ args,
+ options);
+ }
+
+ @Override
+ ClassType superclass() {
+ return null;
+ }
+
+ @Override
+ List<InterfaceType> interfaces() {
+ return superinterfaces();
+ }
+
+ @Override
+ boolean canInvoke(Method method) {
+ // method must be directly in this interface
+ return this.equals(method.declaringType());
+ }
+}
\ No newline at end of file
diff --git a/src/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java b/src/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java
new file mode 100644
index 0000000..61a2330
--- /dev/null
+++ b/src/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.jdi;
+
+import com.sun.jdi.ClassNotLoadedException;
+import com.sun.jdi.ClassType;
+import com.sun.jdi.IncompatibleThreadStateException;
+import com.sun.jdi.InterfaceType;
+import com.sun.jdi.InvalidTypeException;
+import com.sun.jdi.InvocationException;
+import com.sun.jdi.Method;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.Value;
+import com.sun.jdi.VirtualMachine;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A supertype for ReferenceTypes allowing method invocations
+ */
+abstract class InvokableTypeImpl extends ReferenceTypeImpl {
+ /**
+ * The invocation result wrapper
+ * It is necessary because both ClassType and InterfaceType
+ * use their own type to represent the invocation result
+ */
+ static interface InvocationResult {
+ ObjectReferenceImpl getException();
+ ValueImpl getResult();
+ }
+
+ InvokableTypeImpl(VirtualMachine aVm, long aRef) {
+ super(aVm, aRef);
+ }
+
+ /**
+ * Method invocation support.
+ * Shared by ClassType and InterfaceType
+ * @param threadIntf the thread in which to invoke.
+ * @param methodIntf method the {@link Method} to invoke.
+ * @param origArguments the list of {@link Value} arguments bound to the
+ * invoked method. Values from the list are assigned to arguments
+ * in the order they appear in the method signature.
+ * @param options the integer bit flag options.
+ * @return a {@link Value} mirror of the invoked method's return value.
+ * @throws java.lang.IllegalArgumentException if the method is not
+ * a member of this type, if the size of the argument list
+ * does not match the number of declared arguments for the method, or
+ * if the method is not static or is a static initializer.
+ * @throws {@link InvalidTypeException} if any argument in the
+ * argument list is not assignable to the corresponding method argument
+ * type.
+ * @throws ClassNotLoadedException if any argument type has not yet been loaded
+ * through the appropriate class loader.
+ * @throws IncompatibleThreadStateException if the specified thread has not
+ * been suspended by an event.
+ * @throws InvocationException if the method invocation resulted in
+ * an exception in the target VM.
+ * @throws InvalidTypeException If the arguments do not meet this requirement --
+ * Object arguments must be assignment compatible with the argument
+ * type. This implies that the argument type must be
+ * loaded through the enclosing class's class loader.
+ * Primitive arguments must be either assignment compatible with the
+ * argument type or must be convertible to the argument type without loss
+ * of information. See JLS section 5.2 for more information on assignment
+ * compatibility.
+ * @throws VMCannotBeModifiedException if the VirtualMachine is read-only - see {@link VirtualMachine#canBeModified()}.
+ */
+ final public Value invokeMethod(ThreadReference threadIntf, Method methodIntf,
+ List<? extends Value> origArguments, int options)
+ throws InvalidTypeException,
+ ClassNotLoadedException,
+ IncompatibleThreadStateException,
+ InvocationException {
+ validateMirror(threadIntf);
+ validateMirror(methodIntf);
+ validateMirrorsOrNulls(origArguments);
+ MethodImpl method = (MethodImpl) methodIntf;
+ ThreadReferenceImpl thread = (ThreadReferenceImpl) threadIntf;
+ validateMethodInvocation(method);
+ List<? extends Value> arguments = method.validateAndPrepareArgumentsForInvoke(origArguments);
+ ValueImpl[] args = arguments.toArray(new ValueImpl[0]);
+ InvocationResult ret;
+ try {
+ PacketStream stream = sendInvokeCommand(thread, method, args, options);
+ ret = waitForReply(stream);
+ } catch (JDWPException exc) {
+ if (exc.errorCode() == JDWP.Error.INVALID_THREAD) {
+ throw new IncompatibleThreadStateException();
+ } else {
+ throw exc.toJDIException();
+ }
+ }
+ /*
+ * There is an implict VM-wide suspend at the conclusion
+ * of a normal (non-single-threaded) method invoke
+ */
+ if ((options & ClassType.INVOKE_SINGLE_THREADED) == 0) {
+ vm.notifySuspend();
+ }
+ if (ret.getException() != null) {
+ throw new InvocationException(ret.getException());
+ } else {
+ return ret.getResult();
+ }
+ }
+
+ @Override
+ boolean isAssignableTo(ReferenceType type) {
+ ClassTypeImpl superclazz = (ClassTypeImpl) superclass();
+ if (this.equals(type)) {
+ return true;
+ } else if ((superclazz != null) && superclazz.isAssignableTo(type)) {
+ return true;
+ } else {
+ List<InterfaceType> interfaces = interfaces();
+ Iterator<InterfaceType> iter = interfaces.iterator();
+ while (iter.hasNext()) {
+ InterfaceTypeImpl interfaze = (InterfaceTypeImpl) iter.next();
+ if (interfaze.isAssignableTo(type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ @Override
+ final void addVisibleMethods(Map<String, Method> methodMap, Set<InterfaceType> seenInterfaces) {
+ /*
+ * Add methods from
+ * parent types first, so that the methods in this class will
+ * overwrite them in the hash table
+ */
+ Iterator<InterfaceType> iter = interfaces().iterator();
+ while (iter.hasNext()) {
+ InterfaceTypeImpl interfaze = (InterfaceTypeImpl) iter.next();
+ if (!seenInterfaces.contains(interfaze)) {
+ interfaze.addVisibleMethods(methodMap, seenInterfaces);
+ seenInterfaces.add(interfaze);
+ }
+ }
+ ClassTypeImpl clazz = (ClassTypeImpl) superclass();
+ if (clazz != null) {
+ clazz.addVisibleMethods(methodMap, seenInterfaces);
+ }
+ addToMethodMap(methodMap, methods());
+ }
+
+ final void addInterfaces(List<InterfaceType> list) {
+ List<InterfaceType> immediate = interfaces();
+ list.addAll(interfaces());
+ Iterator<InterfaceType> iter = immediate.iterator();
+ while (iter.hasNext()) {
+ InterfaceTypeImpl interfaze = (InterfaceTypeImpl) iter.next();
+ interfaze.addInterfaces(list);
+ }
+ ClassTypeImpl superclass = (ClassTypeImpl) superclass();
+ if (superclass != null) {
+ superclass.addInterfaces(list);
+ }
+ }
+
+ /**
+ * Returns all the implemented interfaces recursively
+ * @return A list of all the implemented interfaces (recursively)
+ */
+ final List<InterfaceType> getAllInterfaces() {
+ List<InterfaceType> all = new ArrayList<>();
+ addInterfaces(all);
+ return all;
+ }
+
+ /**
+ * Shared implementation of {@linkplain ClassType#allMethods()} and
+ * {@linkplain InterfaceType#allMethods()}
+ * @return A list of all methods (recursively)
+ */
+ public final List<Method> allMethods() {
+ ArrayList<Method> list = new ArrayList<>(methods());
+ ClassType clazz = superclass();
+ while (clazz != null) {
+ list.addAll(clazz.methods());
+ clazz = clazz.superclass();
+ }
+ /*
+ * Avoid duplicate checking on each method by iterating through
+ * duplicate-free allInterfaces() rather than recursing
+ */
+ for (InterfaceType interfaze : getAllInterfaces()) {
+ list.addAll(interfaze.methods());
+ }
+ return list;
+ }
+
+ @Override
+ final List<ReferenceType> inheritedTypes() {
+ List<ReferenceType> inherited = new ArrayList<>();
+ if (superclass() != null) {
+ inherited.add(0, superclass()); /* insert at front */
+ }
+ for (ReferenceType rt : interfaces()) {
+ inherited.add(rt);
+ }
+ return inherited;
+ }
+
+ private PacketStream sendInvokeCommand(final ThreadReferenceImpl thread,
+ final MethodImpl method,
+ final ValueImpl[] args,
+ final int options) {
+ CommandSender sender = getInvokeMethodSender(thread, method, args, options);
+ PacketStream stream;
+ if ((options & ClassType.INVOKE_SINGLE_THREADED) != 0) {
+ stream = thread.sendResumingCommand(sender);
+ } else {
+ stream = vm.sendResumingCommand(sender);
+ }
+ return stream;
+ }
+
+ private void validateMethodInvocation(Method method)
+ throws InvalidTypeException,
+ InvocationException {
+ if (!canInvoke(method)) {
+ throw new IllegalArgumentException("Invalid method");
+ }
+ /*
+ * Method must be a static and not a static initializer
+ */
+ if (!method.isStatic()) {
+ throw new IllegalArgumentException("Cannot invoke instance method on a class/interface type");
+ } else if (method.isStaticInitializer()) {
+ throw new IllegalArgumentException("Cannot invoke static initializer");
+ }
+ }
+
+ /**
+ * A subclass will provide specific {@linkplain CommandSender}
+ * @param thread the current invocation thread
+ * @param method the method to invoke
+ * @param args the arguments to pass to the method
+ * @param options the integer bit flag options
+ * @return the specific {@literal CommandSender} instance
+ */
+ abstract CommandSender getInvokeMethodSender(ThreadReferenceImpl thread,
+ MethodImpl method,
+ ValueImpl[] args,
+ int options);
+
+ /**
+ * Waits for the reply to the last sent command
+ * @param stream the stream to listen for the reply on
+ * @return the {@linkplain InvocationResult} instance
+ * @throws JDWPException when something goes wrong in JDWP
+ */
+ abstract InvocationResult waitForReply(PacketStream stream) throws JDWPException;
+
+ /**
+ * Get the {@linkplain ReferenceType} superclass
+ * @return the superclass or null
+ */
+ abstract ClassType superclass();
+
+ /**
+ * Get the implemented/extended interfaces
+ * @return the list of implemented/extended interfaces
+ */
+ abstract List<InterfaceType> interfaces();
+
+ /**
+ * Checks the provided method whether it can be invoked
+ * @param method the method to check
+ * @return {@code TRUE} if the implementation knows how to invoke the method,
+ * {@code FALSE} otherwise
+ */
+ abstract boolean canInvoke(Method method);
+}
diff --git a/src/share/classes/com/sun/tools/jdi/MethodImpl.java b/src/share/classes/com/sun/tools/jdi/MethodImpl.java
index f63ad68..1d93f4c 100644
--- a/src/share/classes/com/sun/tools/jdi/MethodImpl.java
+++ b/src/share/classes/com/sun/tools/jdi/MethodImpl.java
@@ -187,6 +187,13 @@
return isModifierSet(VMModifiers.ABSTRACT);
}
+ public boolean isDefault() {
+ return !isModifierSet(VMModifiers.ABSTRACT) &&
+ !isModifierSet(VMModifiers.STATIC) &&
+ !isModifierSet(VMModifiers.PRIVATE) &&
+ declaringType() instanceof InterfaceType;
+ }
+
public boolean isSynchronized() {
return isModifierSet(VMModifiers.SYNCHRONIZED);
}
diff --git a/src/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java b/src/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java
index 2b1b058..1d5a6c9 100644
--- a/src/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java
+++ b/src/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java
@@ -277,7 +277,6 @@
void validateMethodInvocation(Method method, int options)
throws InvalidTypeException,
InvocationException {
-
/*
* Method must be in this object's class, a superclass, or
* implemented interface
@@ -287,6 +286,19 @@
throw new IllegalArgumentException("Invalid method");
}
+ if (declType instanceof ClassTypeImpl) {
+ validateClassMethodInvocation(method, options);
+ } else if (declType instanceof InterfaceTypeImpl) {
+ validateIfaceMethodInvocation(method, options);
+ } else {
+ throw new InvalidTypeException();
+ }
+ }
+
+ void validateClassMethodInvocation(Method method, int options)
+ throws InvalidTypeException,
+ InvocationException {
+
ClassTypeImpl clazz = invokableReferenceType(method);
/*
@@ -300,9 +312,7 @@
* For nonvirtual invokes, method must have a body
*/
if ((options & INVOKE_NONVIRTUAL) != 0) {
- if (method.declaringType() instanceof InterfaceType) {
- throw new IllegalArgumentException("Interface method");
- } else if (method.isAbstract()) {
+ if (method.isAbstract()) {
throw new IllegalArgumentException("Abstract method");
}
}
@@ -324,7 +334,7 @@
*/
Method invoker = clazz.concreteMethodByName(method.name(),
method.signature());
- // isAssignableFrom check above guarantees non-null
+ // invoker is supposed to be non-null under normal circumstances
invokedClass = (ClassTypeImpl)invoker.declaringType();
}
/* The above code is left over from previous versions.
@@ -332,6 +342,17 @@
*/
}
+ void validateIfaceMethodInvocation(Method method, int options)
+ throws InvalidTypeException,
+ InvocationException {
+ /*
+ * Only default methods allowed for nonvirtual invokes
+ */
+ if (!method.isDefault()) {
+ throw new IllegalArgumentException("Not a default method");
+ }
+ }
+
PacketStream sendInvokeCommand(final ThreadReferenceImpl thread,
final ClassTypeImpl refType,
final MethodImpl method,
@@ -370,7 +391,10 @@
ThreadReferenceImpl thread = (ThreadReferenceImpl)threadIntf;
if (method.isStatic()) {
- if (referenceType() instanceof ClassType) {
+ if (referenceType() instanceof InterfaceType) {
+ InterfaceType type = (InterfaceType)referenceType();
+ return type.invokeMethod(thread, method, origArguments, options);
+ } else if (referenceType() instanceof ClassType) {
ClassType type = (ClassType)referenceType();
return type.invokeMethod(thread, method, origArguments, options);
} else {
diff --git a/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java b/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
index 29da75d..be98d5e 100644
--- a/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
+++ b/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
@@ -511,7 +511,7 @@
methodMap.put(method.name().concat(method.signature()), method);
}
- abstract void addVisibleMethods(Map<String, Method> methodMap);
+ abstract void addVisibleMethods(Map<String, Method> methodMap, Set<InterfaceType> seenInterfaces);
public List<Method> visibleMethods() {
/*
@@ -520,7 +520,7 @@
* concatenation of name and signature.
*/
Map<String, Method> map = new HashMap<String, Method>();
- addVisibleMethods(map);
+ addVisibleMethods(map, new HashSet<InterfaceType>());
/*
* ... but the hash map destroys order. Methods should be
diff --git a/src/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java b/src/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java
index e41b295..3704b41 100644
--- a/src/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java
+++ b/src/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java
@@ -48,7 +48,7 @@
private ResourceBundle messages = null;
private int vmSequenceNumber = 0;
private static final int majorVersion = 1;
- private static final int minorVersion = 6;
+ private static final int minorVersion = 8;
private static final Object lock = new Object();
private static VirtualMachineManagerImpl vmm;
diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
index da78e44..cdbbebc 100644
--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
+++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
@@ -62,7 +62,7 @@
private static final String CLL_SIG = "(L" + CLS + ";L" + OBJ + ";)L" + OBJ + ";";
/** Name of its super class*/
- private static final String superName = LF;
+ private static final String superName = OBJ;
/** Name of new class */
private final String className;
@@ -97,7 +97,7 @@
if (DUMP_CLASS_FILES) {
className = makeDumpableClassName(className);
}
- this.className = superName + "$" + className;
+ this.className = LF + "$" + className;
this.sourceFile = "LambdaForm$" + className;
this.lambdaForm = lambdaForm;
this.invokerName = invokerName;
diff --git a/src/share/classes/java/net/URLClassLoader.java b/src/share/classes/java/net/URLClassLoader.java
index c88c707..a75ac30 100644
--- a/src/share/classes/java/net/URLClassLoader.java
+++ b/src/share/classes/java/net/URLClassLoader.java
@@ -354,10 +354,11 @@
* @exception NullPointerException if {@code name} is {@code null}.
*/
protected Class<?> findClass(final String name)
- throws ClassNotFoundException
+ throws ClassNotFoundException
{
+ final Class<?> result;
try {
- return AccessController.doPrivileged(
+ result = AccessController.doPrivileged(
new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws ClassNotFoundException {
String path = name.replace('.', '/').concat(".class");
@@ -369,13 +370,17 @@
throw new ClassNotFoundException(name, e);
}
} else {
- throw new ClassNotFoundException(name);
+ return null;
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
+ if (result == null) {
+ throw new ClassNotFoundException(name);
+ }
+ return result;
}
/*
diff --git a/src/share/classes/java/security/KeyPairGenerator.java b/src/share/classes/java/security/KeyPairGenerator.java
index c09d251..2056768 100644
--- a/src/share/classes/java/security/KeyPairGenerator.java
+++ b/src/share/classes/java/security/KeyPairGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
import sun.security.jca.*;
import sun.security.jca.GetInstance.Instance;
+import sun.security.util.Debug;
/**
* The KeyPairGenerator class is used to generate pairs of
@@ -126,6 +127,11 @@
public abstract class KeyPairGenerator extends KeyPairGeneratorSpi {
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("keypairgenerator");
+
private final String algorithm;
// The provider
@@ -167,6 +173,12 @@
kpg = new Delegate(spi, algorithm);
}
kpg.provider = instance.provider;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyPairGenerator." + algorithm +
+ " algorithm from: " + kpg.provider.getName());
+ }
+
return kpg;
}
@@ -557,6 +569,11 @@
provider = instance.provider;
this.serviceIterator = serviceIterator;
initType = I_NONE;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyPairGenerator." + algorithm +
+ " algorithm from: " + provider.getName());
+ }
}
/**
diff --git a/src/share/classes/java/security/KeyStore.java b/src/share/classes/java/security/KeyStore.java
index 80bf17d..4278369 100644
--- a/src/share/classes/java/security/KeyStore.java
+++ b/src/share/classes/java/security/KeyStore.java
@@ -37,6 +37,8 @@
import javax.security.auth.DestroyFailedException;
import javax.security.auth.callback.*;
+import sun.security.util.Debug;
+
/**
* This class represents a storage facility for cryptographic
* keys and certificates.
@@ -177,6 +179,11 @@
public class KeyStore {
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("keystore");
+
/*
* Constant to lookup in the Security properties file to determine
* the default keystore type.
@@ -801,6 +808,11 @@
this.keyStoreSpi = keyStoreSpi;
this.provider = provider;
this.type = type;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyStore." + type.toUpperCase() + " type from: " +
+ this.provider.getName());
+ }
}
/**
diff --git a/src/share/classes/java/security/MessageDigest.java b/src/share/classes/java/security/MessageDigest.java
index 60d41ff..cf3e3a3 100644
--- a/src/share/classes/java/security/MessageDigest.java
+++ b/src/share/classes/java/security/MessageDigest.java
@@ -35,6 +35,8 @@
import java.nio.ByteBuffer;
+import sun.security.util.Debug;
+
/**
* This MessageDigest class provides applications the functionality of a
* message digest algorithm, such as SHA-1 or SHA-256.
@@ -103,6 +105,11 @@
public abstract class MessageDigest extends MessageDigestSpi {
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("messagedigest");
+
private String algorithm;
// The state of this digest
@@ -156,18 +163,23 @@
public static MessageDigest getInstance(String algorithm)
throws NoSuchAlgorithmException {
try {
+ MessageDigest md;
Object[] objs = Security.getImpl(algorithm, "MessageDigest",
(String)null);
if (objs[0] instanceof MessageDigest) {
- MessageDigest md = (MessageDigest)objs[0];
- md.provider = (Provider)objs[1];
- return md;
+ md = (MessageDigest)objs[0];
} else {
- MessageDigest delegate =
- new Delegate((MessageDigestSpi)objs[0], algorithm);
- delegate.provider = (Provider)objs[1];
- return delegate;
+ md = new Delegate((MessageDigestSpi)objs[0], algorithm);
}
+ md.provider = (Provider)objs[1];
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("MessageDigest." + algorithm +
+ " algorithm from: " + md.provider.getName());
+ }
+
+ return md;
+
} catch(NoSuchProviderException e) {
throw new NoSuchAlgorithmException(algorithm + " not found");
}
diff --git a/src/share/classes/java/security/SecureRandom.java b/src/share/classes/java/security/SecureRandom.java
index b9ae722..3481e21 100644
--- a/src/share/classes/java/security/SecureRandom.java
+++ b/src/share/classes/java/security/SecureRandom.java
@@ -32,6 +32,7 @@
import sun.security.jca.*;
import sun.security.jca.GetInstance.Instance;
+import sun.security.util.Debug;
/**
* This class provides a cryptographically strong random number
@@ -92,6 +93,11 @@
public class SecureRandom extends java.util.Random {
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("securerandom");
+
/**
* The provider.
*
@@ -234,6 +240,11 @@
this.secureRandomSpi = secureRandomSpi;
this.provider = provider;
this.algorithm = algorithm;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("SecureRandom." + algorithm +
+ " algorithm from: " + this.provider.getName());
+ }
}
/**
diff --git a/src/share/classes/java/security/Signature.java b/src/share/classes/java/security/Signature.java
index 7c5bd96..60a7e01 100644
--- a/src/share/classes/java/security/Signature.java
+++ b/src/share/classes/java/security/Signature.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -121,6 +121,11 @@
private static final Debug debug =
Debug.getInstance("jca", "Signature");
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("signature");
+
/*
* The algorithm for this signature object.
* This value is used to map an OID to the particular algorithm.
@@ -451,6 +456,11 @@
throws InvalidKeyException {
engineInitVerify(publicKey);
state = VERIFY;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " verification algorithm from: " + this.provider.getName());
+ }
}
/**
@@ -495,6 +505,11 @@
PublicKey publicKey = certificate.getPublicKey();
engineInitVerify(publicKey);
state = VERIFY;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " verification algorithm from: " + this.provider.getName());
+ }
}
/**
@@ -511,6 +526,11 @@
throws InvalidKeyException {
engineInitSign(privateKey);
state = SIGN;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " signing algorithm from: " + this.provider.getName());
+ }
}
/**
@@ -529,6 +549,11 @@
throws InvalidKeyException {
engineInitSign(privateKey, random);
state = SIGN;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " signing algorithm from: " + this.provider.getName());
+ }
}
/**
diff --git a/src/share/classes/java/util/concurrent/ForkJoinPool.java b/src/share/classes/java/util/concurrent/ForkJoinPool.java
index 9f5e149..8b6ed6d 100644
--- a/src/share/classes/java/util/concurrent/ForkJoinPool.java
+++ b/src/share/classes/java/util/concurrent/ForkJoinPool.java
@@ -49,6 +49,7 @@
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
import java.security.AccessControlContext;
import java.security.ProtectionDomain;
import java.security.Permissions;
@@ -80,9 +81,9 @@
*
* <p>For applications that require separate or custom pools, a {@code
* ForkJoinPool} may be constructed with a given target parallelism
- * level; by default, equal to the number of available processors. The
- * pool attempts to maintain enough active (or available) threads by
- * dynamically adding, suspending, or resuming internal worker
+ * level; by default, equal to the number of available processors.
+ * The pool attempts to maintain enough active (or available) threads
+ * by dynamically adding, suspending, or resuming internal worker
* threads, even if some tasks are stalled waiting to join others.
* However, no such adjustments are guaranteed in the face of blocked
* I/O or other unmanaged synchronization. The nested {@link
@@ -178,7 +179,14 @@
* that may be stolen by other workers. Preference rules give
* first priority to processing tasks from their own queues (LIFO
* or FIFO, depending on mode), then to randomized FIFO steals of
- * tasks in other queues.
+ * tasks in other queues. This framework began as vehicle for
+ * supporting tree-structured parallelism using work-stealing.
+ * Over time, its scalability advantages led to extensions and
+ * changes to better support more diverse usage contexts. Because
+ * most internal methods and nested classes are interrelated,
+ * their main rationale and descriptions are presented here;
+ * individual methods and nested classes contain only brief
+ * comments about details.
*
* WorkQueues
* ==========
@@ -198,201 +206,318 @@
* (http://research.sun.com/scalable/pubs/index.html) and
* "Idempotent work stealing" by Michael, Saraswat, and Vechev,
* PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186).
- * See also "Correct and Efficient Work-Stealing for Weak Memory
- * Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
- * (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an
- * analysis of memory ordering (atomic, volatile etc) issues. The
- * main differences ultimately stem from GC requirements that we
- * null out taken slots as soon as we can, to maintain as small a
- * footprint as possible even in programs generating huge numbers
- * of tasks. To accomplish this, we shift the CAS arbitrating pop
- * vs poll (steal) from being on the indices ("base" and "top") to
- * the slots themselves. So, both a successful pop and poll
- * mainly entail a CAS of a slot from non-null to null. Because
- * we rely on CASes of references, we do not need tag bits on base
- * or top. They are simple ints as used in any circular
+ * The main differences ultimately stem from GC requirements that
+ * we null out taken slots as soon as we can, to maintain as small
+ * a footprint as possible even in programs generating huge
+ * numbers of tasks. To accomplish this, we shift the CAS
+ * arbitrating pop vs poll (steal) from being on the indices
+ * ("base" and "top") to the slots themselves.
+ *
+ * Adding tasks then takes the form of a classic array push(task):
+ * q.array[q.top] = task; ++q.top;
+ *
+ * (The actual code needs to null-check and size-check the array,
+ * properly fence the accesses, and possibly signal waiting
+ * workers to start scanning -- see below.) Both a successful pop
+ * and poll mainly entail a CAS of a slot from non-null to null.
+ *
+ * The pop operation (always performed by owner) is:
+ * if ((base != top) and
+ * (the task at top slot is not null) and
+ * (CAS slot to null))
+ * decrement top and return task;
+ *
+ * And the poll operation (usually by a stealer) is
+ * if ((base != top) and
+ * (the task at base slot is not null) and
+ * (base has not changed) and
+ * (CAS slot to null))
+ * increment base and return task;
+ *
+ * Because we rely on CASes of references, we do not need tag bits
+ * on base or top. They are simple ints as used in any circular
* array-based queue (see for example ArrayDeque). Updates to the
- * indices must still be ordered in a way that guarantees that top
- * == base means the queue is empty, but otherwise may err on the
- * side of possibly making the queue appear nonempty when a push,
- * pop, or poll have not fully committed. Note that this means
- * that the poll operation, considered individually, is not
- * wait-free. One thief cannot successfully continue until another
- * in-progress one (or, if previously empty, a push) completes.
- * However, in the aggregate, we ensure at least probabilistic
+ * indices guarantee that top == base means the queue is empty,
+ * but otherwise may err on the side of possibly making the queue
+ * appear nonempty when a push, pop, or poll have not fully
+ * committed. (Method isEmpty() checks the case of a partially
+ * completed removal of the last element.) Because of this, the
+ * poll operation, considered individually, is not wait-free. One
+ * thief cannot successfully continue until another in-progress
+ * one (or, if previously empty, a push) completes. However, in
+ * the aggregate, we ensure at least probabilistic
* non-blockingness. If an attempted steal fails, a thief always
* chooses a different random victim target to try next. So, in
* order for one thief to progress, it suffices for any
* in-progress poll or new push on any empty queue to
* complete. (This is why we normally use method pollAt and its
* variants that try once at the apparent base index, else
- * consider alternative actions, rather than method poll.)
+ * consider alternative actions, rather than method poll, which
+ * retries.)
*
- * This approach also enables support of a user mode in which local
- * task processing is in FIFO, not LIFO order, simply by using
- * poll rather than pop. This can be useful in message-passing
- * frameworks in which tasks are never joined. However neither
- * mode considers affinities, loads, cache localities, etc, so
- * rarely provide the best possible performance on a given
- * machine, but portably provide good throughput by averaging over
- * these factors. (Further, even if we did try to use such
- * information, we do not usually have a basis for exploiting it.
- * For example, some sets of tasks profit from cache affinities,
- * but others are harmed by cache pollution effects.)
+ * This approach also enables support of a user mode in which
+ * local task processing is in FIFO, not LIFO order, simply by
+ * using poll rather than pop. This can be useful in
+ * message-passing frameworks in which tasks are never joined.
+ * However neither mode considers affinities, loads, cache
+ * localities, etc, so rarely provide the best possible
+ * performance on a given machine, but portably provide good
+ * throughput by averaging over these factors. Further, even if
+ * we did try to use such information, we do not usually have a
+ * basis for exploiting it. For example, some sets of tasks
+ * profit from cache affinities, but others are harmed by cache
+ * pollution effects. Additionally, even though it requires
+ * scanning, long-term throughput is often best using random
+ * selection rather than directed selection policies, so cheap
+ * randomization of sufficient quality is used whenever
+ * applicable. Various Marsaglia XorShifts (some with different
+ * shift constants) are inlined at use points.
*
* WorkQueues are also used in a similar way for tasks submitted
* to the pool. We cannot mix these tasks in the same queues used
- * for work-stealing (this would contaminate lifo/fifo
- * processing). Instead, we randomly associate submission queues
+ * by workers. Instead, we randomly associate submission queues
* with submitting threads, using a form of hashing. The
* ThreadLocalRandom probe value serves as a hash code for
* choosing existing queues, and may be randomly repositioned upon
* contention with other submitters. In essence, submitters act
* like workers except that they are restricted to executing local
* tasks that they submitted (or in the case of CountedCompleters,
- * others with the same root task). However, because most
- * shared/external queue operations are more expensive than
- * internal, and because, at steady state, external submitters
- * will compete for CPU with workers, ForkJoinTask.join and
- * related methods disable them from repeatedly helping to process
- * tasks if all workers are active. Insertion of tasks in shared
+ * others with the same root task). Insertion of tasks in shared
* mode requires a lock (mainly to protect in the case of
- * resizing) but we use only a simple spinlock (using bits in
- * field qlock), because submitters encountering a busy queue move
- * on to try or create other queues -- they block only when
- * creating and registering new queues.
+ * resizing) but we use only a simple spinlock (using field
+ * qlock), because submitters encountering a busy queue move on to
+ * try or create other queues -- they block only when creating and
+ * registering new queues. Additionally, "qlock" saturates to an
+ * unlockable value (-1) at shutdown. Unlocking still can be and
+ * is performed by cheaper ordered writes of "qlock" in successful
+ * cases, but uses CAS in unsuccessful cases.
*
* Management
* ==========
*
* The main throughput advantages of work-stealing stem from
* decentralized control -- workers mostly take tasks from
- * themselves or each other. We cannot negate this in the
- * implementation of other management responsibilities. The main
- * tactic for avoiding bottlenecks is packing nearly all
- * essentially atomic control state into two volatile variables
- * that are by far most often read (not written) as status and
- * consistency checks.
+ * themselves or each other, at rates that can exceed a billion
+ * per second. The pool itself creates, activates (enables
+ * scanning for and running tasks), deactivates, blocks, and
+ * terminates threads, all with minimal central information.
+ * There are only a few properties that we can globally track or
+ * maintain, so we pack them into a small number of variables,
+ * often maintaining atomicity without blocking or locking.
+ * Nearly all essentially atomic control state is held in two
+ * volatile variables that are by far most often read (not
+ * written) as status and consistency checks. (Also, field
+ * "config" holds unchanging configuration state.)
*
- * Field "ctl" contains 64 bits holding all the information needed
- * to atomically decide to add, inactivate, enqueue (on an event
+ * Field "ctl" contains 64 bits holding information needed to
+ * atomically decide to add, inactivate, enqueue (on an event
* queue), dequeue, and/or re-activate workers. To enable this
* packing, we restrict maximum parallelism to (1<<15)-1 (which is
* far in excess of normal operating range) to allow ids, counts,
* and their negations (used for thresholding) to fit into 16bit
- * fields.
+ * subfields.
*
- * Field "plock" is a form of sequence lock with a saturating
- * shutdown bit (similarly for per-queue "qlocks"), mainly
- * protecting updates to the workQueues array, as well as to
- * enable shutdown. When used as a lock, it is normally only very
- * briefly held, so is nearly always available after at most a
- * brief spin, but we use a monitor-based backup strategy to
- * block when needed.
+ * Field "runState" holds lockable state bits (STARTED, STOP, etc)
+ * also protecting updates to the workQueues array. When used as
+ * a lock, it is normally held only for a few instructions (the
+ * only exceptions are one-time array initialization and uncommon
+ * resizing), so is nearly always available after at most a brief
+ * spin. But to be extra-cautious, after spinning, method
+ * awaitRunStateLock (called only if an initial CAS fails), uses a
+ * wait/notify mechanics on a builtin monitor to block when
+ * (rarely) needed. This would be a terrible idea for a highly
+ * contended lock, but most pools run without the lock ever
+ * contending after the spin limit, so this works fine as a more
+ * conservative alternative. Because we don't otherwise have an
+ * internal Object to use as a monitor, the "stealCounter" (an
+ * AtomicLong) is used when available (it too must be lazily
+ * initialized; see externalSubmit).
+ *
+ * Usages of "runState" vs "ctl" interact in only one case:
+ * deciding to add a worker thread (see tryAddWorker), in which
+ * case the ctl CAS is performed while the lock is held.
*
* Recording WorkQueues. WorkQueues are recorded in the
- * "workQueues" array that is created upon first use and expanded
- * if necessary. Updates to the array while recording new workers
- * and unrecording terminated ones are protected from each other
- * by a lock but the array is otherwise concurrently readable, and
- * accessed directly. To simplify index-based operations, the
- * array size is always a power of two, and all readers must
- * tolerate null slots. Worker queues are at odd indices. Shared
- * (submission) queues are at even indices, up to a maximum of 64
- * slots, to limit growth even if array needs to expand to add
- * more workers. Grouping them together in this way simplifies and
- * speeds up task scanning.
+ * "workQueues" array. The array is created upon first use (see
+ * externalSubmit) and expanded if necessary. Updates to the
+ * array while recording new workers and unrecording terminated
+ * ones are protected from each other by the runState lock, but
+ * the array is otherwise concurrently readable, and accessed
+ * directly. We also ensure that reads of the array reference
+ * itself never become too stale. To simplify index-based
+ * operations, the array size is always a power of two, and all
+ * readers must tolerate null slots. Worker queues are at odd
+ * indices. Shared (submission) queues are at even indices, up to
+ * a maximum of 64 slots, to limit growth even if array needs to
+ * expand to add more workers. Grouping them together in this way
+ * simplifies and speeds up task scanning.
*
* All worker thread creation is on-demand, triggered by task
* submissions, replacement of terminated workers, and/or
* compensation for blocked workers. However, all other support
* code is set up to work with other policies. To ensure that we
- * do not hold on to worker references that would prevent GC, ALL
+ * do not hold on to worker references that would prevent GC, All
* accesses to workQueues are via indices into the workQueues
* array (which is one source of some of the messy code
* constructions here). In essence, the workQueues array serves as
- * a weak reference mechanism. Thus for example the wait queue
- * field of ctl stores indices, not references. Access to the
- * workQueues in associated methods (for example signalWork) must
- * both index-check and null-check the IDs. All such accesses
- * ignore bad IDs by returning out early from what they are doing,
- * since this can only be associated with termination, in which
- * case it is OK to give up. All uses of the workQueues array
- * also check that it is non-null (even if previously
- * non-null). This allows nulling during termination, which is
- * currently not necessary, but remains an option for
- * resource-revocation-based shutdown schemes. It also helps
- * reduce JIT issuance of uncommon-trap code, which tends to
- * unnecessarily complicate control flow in some methods.
+ * a weak reference mechanism. Thus for example the stack top
+ * subfield of ctl stores indices, not references.
*
- * Event Queuing. Unlike HPC work-stealing frameworks, we cannot
- * let workers spin indefinitely scanning for tasks when none can
- * be found immediately, and we cannot start/resume workers unless
- * there appear to be tasks available. On the other hand, we must
- * quickly prod them into action when new tasks are submitted or
- * generated. In many usages, ramp-up time to activate workers is
- * the main limiting factor in overall performance (this is
- * compounded at program start-up by JIT compilation and
- * allocation). So we try to streamline this as much as possible.
- * We park/unpark workers after placing in an event wait queue
- * when they cannot find work. This "queue" is actually a simple
- * Treiber stack, headed by the "id" field of ctl, plus a 15bit
- * counter value (that reflects the number of times a worker has
- * been inactivated) to avoid ABA effects (we need only as many
- * version numbers as worker threads). Successors are held in
- * field WorkQueue.nextWait. Queuing deals with several intrinsic
- * races, mainly that a task-producing thread can miss seeing (and
- * signalling) another thread that gave up looking for work but
- * has not yet entered the wait queue. We solve this by requiring
- * a full sweep of all workers (via repeated calls to method
- * scan()) both before and after a newly waiting worker is added
- * to the wait queue. Because enqueued workers may actually be
- * rescanning rather than waiting, we set and clear the "parker"
+ * Queuing Idle Workers. Unlike HPC work-stealing frameworks, we
+ * cannot let workers spin indefinitely scanning for tasks when
+ * none can be found immediately, and we cannot start/resume
+ * workers unless there appear to be tasks available. On the
+ * other hand, we must quickly prod them into action when new
+ * tasks are submitted or generated. In many usages, ramp-up time
+ * to activate workers is the main limiting factor in overall
+ * performance, which is compounded at program start-up by JIT
+ * compilation and allocation. So we streamline this as much as
+ * possible.
+ *
+ * The "ctl" field atomically maintains active and total worker
+ * counts as well as a queue to place waiting threads so they can
+ * be located for signalling. Active counts also play the role of
+ * quiescence indicators, so are decremented when workers believe
+ * that there are no more tasks to execute. The "queue" is
+ * actually a form of Treiber stack. A stack is ideal for
+ * activating threads in most-recently used order. This improves
+ * performance and locality, outweighing the disadvantages of
+ * being prone to contention and inability to release a worker
+ * unless it is topmost on stack. We park/unpark workers after
+ * pushing on the idle worker stack (represented by the lower
+ * 32bit subfield of ctl) when they cannot find work. The top
+ * stack state holds the value of the "scanState" field of the
+ * worker: its index and status, plus a version counter that, in
+ * addition to the count subfields (also serving as version
+ * stamps) provide protection against Treiber stack ABA effects.
+ *
+ * Field scanState is used by both workers and the pool to manage
+ * and track whether a worker is INACTIVE (possibly blocked
+ * waiting for a signal), or SCANNING for tasks (when neither hold
+ * it is busy running tasks). When a worker is inactivated, its
+ * scanState field is set, and is prevented from executing tasks,
+ * even though it must scan once for them to avoid queuing
+ * races. Note that scanState updates lag queue CAS releases so
+ * usage requires care. When queued, the lower 16 bits of
+ * scanState must hold its pool index. So we place the index there
+ * upon initialization (see registerWorker) and otherwise keep it
+ * there or restore it when necessary.
+ *
+ * Memory ordering. See "Correct and Efficient Work-Stealing for
+ * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
+ * (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an
+ * analysis of memory ordering requirements in work-stealing
+ * algorithms similar to the one used here. We usually need
+ * stronger than minimal ordering because we must sometimes signal
+ * workers, requiring Dekker-like full-fences to avoid lost
+ * signals. Arranging for enough ordering without expensive
+ * over-fencing requires tradeoffs among the supported means of
+ * expressing access constraints. The most central operations,
+ * taking from queues and updating ctl state, require full-fence
+ * CAS. Array slots are read using the emulation of volatiles
+ * provided by Unsafe. Access from other threads to WorkQueue
+ * base, top, and array requires a volatile load of the first of
+ * any of these read. We use the convention of declaring the
+ * "base" index volatile, and always read it before other fields.
+ * The owner thread must ensure ordered updates, so writes use
+ * ordered intrinsics unless they can piggyback on those for other
+ * writes. Similar conventions and rationales hold for other
+ * WorkQueue fields (such as "currentSteal") that are only written
+ * by owners but observed by others.
+ *
+ * Creating workers. To create a worker, we pre-increment total
+ * count (serving as a reservation), and attempt to construct a
+ * ForkJoinWorkerThread via its factory. Upon construction, the
+ * new thread invokes registerWorker, where it constructs a
+ * WorkQueue and is assigned an index in the workQueues array
+ * (expanding the array if necessary). The thread is then
+ * started. Upon any exception across these steps, or null return
+ * from factory, deregisterWorker adjusts counts and records
+ * accordingly. If a null return, the pool continues running with
+ * fewer than the target number workers. If exceptional, the
+ * exception is propagated, generally to some external caller.
+ * Worker index assignment avoids the bias in scanning that would
+ * occur if entries were sequentially packed starting at the front
+ * of the workQueues array. We treat the array as a simple
+ * power-of-two hash table, expanding as needed. The seedIndex
+ * increment ensures no collisions until a resize is needed or a
+ * worker is deregistered and replaced, and thereafter keeps
+ * probability of collision low. We cannot use
+ * ThreadLocalRandom.getProbe() for similar purposes here because
+ * the thread has not started yet, but do so for creating
+ * submission queues for existing external threads.
+ *
+ * Deactivation and waiting. Queuing encounters several intrinsic
+ * races; most notably that a task-producing thread can miss
+ * seeing (and signalling) another thread that gave up looking for
+ * work but has not yet entered the wait queue. When a worker
+ * cannot find a task to steal, it deactivates and enqueues. Very
+ * often, the lack of tasks is transient due to GC or OS
+ * scheduling. To reduce false-alarm deactivation, scanners
+ * compute checksums of queue states during sweeps. (The
+ * stability checks used here and elsewhere are probabilistic
+ * variants of snapshot techniques -- see Herlihy & Shavit.)
+ * Workers give up and try to deactivate only after the sum is
+ * stable across scans. Further, to avoid missed signals, they
+ * repeat this scanning process after successful enqueuing until
+ * again stable. In this state, the worker cannot take/run a task
+ * it sees until it is released from the queue, so the worker
+ * itself eventually tries to release itself or any successor (see
+ * tryRelease). Otherwise, upon an empty scan, a deactivated
+ * worker uses an adaptive local spin construction (see awaitWork)
+ * before blocking (via park). Note the unusual conventions about
+ * Thread.interrupts surrounding parking and other blocking:
+ * Because interrupts are used solely to alert threads to check
+ * termination, which is checked anyway upon blocking, we clear
+ * status (using Thread.interrupted) before any call to park, so
+ * that park does not immediately return due to status being set
+ * via some other unrelated call to interrupt in user code.
+ *
+ * Signalling and activation. Workers are created or activated
+ * only when there appears to be at least one task they might be
+ * able to find and execute. Upon push (either by a worker or an
+ * external submission) to a previously (possibly) empty queue,
+ * workers are signalled if idle, or created if fewer exist than
+ * the given parallelism level. These primary signals are
+ * buttressed by others whenever other threads remove a task from
+ * a queue and notice that there are other tasks there as well.
+ * On most platforms, signalling (unpark) overhead time is
+ * noticeably long, and the time between signalling a thread and
+ * it actually making progress can be very noticeably long, so it
+ * is worth offloading these delays from critical paths as much as
+ * possible. Also, because inactive workers are often rescanning
+ * or spinning rather than blocking, we set and clear the "parker"
* field of WorkQueues to reduce unnecessary calls to unpark.
* (This requires a secondary recheck to avoid missed signals.)
- * Note the unusual conventions about Thread.interrupts
- * surrounding parking and other blocking: Because interrupts are
- * used solely to alert threads to check termination, which is
- * checked anyway upon blocking, we clear status (using
- * Thread.interrupted) before any call to park, so that park does
- * not immediately return due to status being set via some other
- * unrelated call to interrupt in user code.
- *
- * Signalling. We create or wake up workers only when there
- * appears to be at least one task they might be able to find and
- * execute. When a submission is added or another worker adds a
- * task to a queue that has fewer than two tasks, they signal
- * waiting workers (or trigger creation of new ones if fewer than
- * the given parallelism level -- signalWork). These primary
- * signals are buttressed by others whenever other threads remove
- * a task from a queue and notice that there are other tasks there
- * as well. So in general, pools will be over-signalled. On most
- * platforms, signalling (unpark) overhead time is noticeably
- * long, and the time between signalling a thread and it actually
- * making progress can be very noticeably long, so it is worth
- * offloading these delays from critical paths as much as
- * possible. Additionally, workers spin-down gradually, by staying
- * alive so long as they see the ctl state changing. Similar
- * stability-sensing techniques are also used before blocking in
- * awaitJoin and helpComplete.
*
* Trimming workers. To release resources after periods of lack of
* use, a worker starting to wait when the pool is quiescent will
- * time out and terminate if the pool has remained quiescent for a
- * given period -- a short period if there are more threads than
- * parallelism, longer as the number of threads decreases. This
- * will slowly propagate, eventually terminating all workers after
- * periods of non-use.
+ * time out and terminate (see awaitWork) if the pool has remained
+ * quiescent for period IDLE_TIMEOUT, increasing the period as the
+ * number of threads decreases, eventually removing all workers.
+ * Also, when more than two spare threads exist, excess threads
+ * are immediately terminated at the next quiescent point.
+ * (Padding by two avoids hysteresis.)
*
- * Shutdown and Termination. A call to shutdownNow atomically sets
- * a plock bit and then (non-atomically) sets each worker's
- * qlock status, cancels all unprocessed tasks, and wakes up
- * all waiting workers. Detecting whether termination should
- * commence after a non-abrupt shutdown() call requires more work
- * and bookkeeping. We need consensus about quiescence (i.e., that
- * there is no more work). The active count provides a primary
- * indication but non-abrupt shutdown still requires a rechecking
- * scan for any workers that are inactive but not queued.
+ * Shutdown and Termination. A call to shutdownNow invokes
+ * tryTerminate to atomically set a runState bit. The calling
+ * thread, as well as every other worker thereafter terminating,
+ * helps terminate others by setting their (qlock) status,
+ * cancelling their unprocessed tasks, and waking them up, doing
+ * so repeatedly until stable (but with a loop bounded by the
+ * number of workers). Calls to non-abrupt shutdown() preface
+ * this by checking whether termination should commence. This
+ * relies primarily on the active count bits of "ctl" maintaining
+ * consensus -- tryTerminate is called from awaitWork whenever
+ * quiescent. However, external submitters do not take part in
+ * this consensus. So, tryTerminate sweeps through queues (until
+ * stable) to ensure lack of in-flight submissions and workers
+ * about to process them before triggering the "STOP" phase of
+ * termination. (Note: there is an intrinsic conflict if
+ * helpQuiescePool is called when shutdown is enabled. Both wait
+ * for quiescence, but tryTerminate is biased to not trigger until
+ * helpQuiescePool completes.)
+ *
*
* Joining Tasks
* =============
@@ -403,9 +528,9 @@
* just let them block (as in Thread.join). We also cannot just
* reassign the joiner's run-time stack with another and replace
* it later, which would be a form of "continuation", that even if
- * possible is not necessarily a good idea since we sometimes need
- * both an unblocked task and its continuation to progress.
- * Instead we combine two tactics:
+ * possible is not necessarily a good idea since we may need both
+ * an unblocked task and its continuation to progress. Instead we
+ * combine two tactics:
*
* Helping: Arranging for the joiner to execute some task that it
* would be running if the steal had not occurred.
@@ -425,16 +550,16 @@
* The ManagedBlocker extension API can't use helping so relies
* only on compensation in method awaitBlocker.
*
- * The algorithm in tryHelpStealer entails a form of "linear"
- * helping: Each worker records (in field currentSteal) the most
- * recent task it stole from some other worker. Plus, it records
- * (in field currentJoin) the task it is currently actively
- * joining. Method tryHelpStealer uses these markers to try to
- * find a worker to help (i.e., steal back a task from and execute
- * it) that could hasten completion of the actively joined task.
- * In essence, the joiner executes a task that would be on its own
- * local deque had the to-be-joined task not been stolen. This may
- * be seen as a conservative variant of the approach in Wagner &
+ * The algorithm in helpStealer entails a form of "linear
+ * helping". Each worker records (in field currentSteal) the most
+ * recent task it stole from some other worker (or a submission).
+ * It also records (in field currentJoin) the task it is currently
+ * actively joining. Method helpStealer uses these markers to try
+ * to find a worker to help (i.e., steal back a task from and
+ * execute it) that could hasten completion of the actively joined
+ * task. Thus, the joiner executes a task that would be on its
+ * own local deque had the to-be-joined task not been stolen. This
+ * is a conservative variant of the approach described in Wagner &
* Calder "Leapfrogging: a portable technique for implementing
* efficient futures" SIGPLAN Notices, 1993
* (http://portal.acm.org/citation.cfm?id=155354). It differs in
@@ -452,37 +577,40 @@
* which means that we miss links in the chain during long-lived
* tasks, GC stalls etc (which is OK since blocking in such cases
* is usually a good idea). (4) We bound the number of attempts
- * to find work (see MAX_HELP) and fall back to suspending the
+ * to find work using checksums and fall back to suspending the
* worker and if necessary replacing it with another.
*
- * Helping actions for CountedCompleters are much simpler: Method
- * helpComplete can take and execute any task with the same root
- * as the task being waited on. However, this still entails some
- * traversal of completer chains, so is less efficient than using
- * CountedCompleters without explicit joins.
+ * Helping actions for CountedCompleters do not require tracking
+ * currentJoins: Method helpComplete takes and executes any task
+ * with the same root as the task being waited on (preferring
+ * local pops to non-local polls). However, this still entails
+ * some traversal of completer chains, so is less efficient than
+ * using CountedCompleters without explicit joins.
*
- * It is impossible to keep exactly the target parallelism number
- * of threads running at any given time. Determining the
- * existence of conservatively safe helping targets, the
- * availability of already-created spares, and the apparent need
- * to create new spares are all racy, so we rely on multiple
- * retries of each. Compensation in the apparent absence of
- * helping opportunities is challenging to control on JVMs, where
- * GC and other activities can stall progress of tasks that in
- * turn stall out many other dependent tasks, without us being
- * able to determine whether they will ever require compensation.
- * Even though work-stealing otherwise encounters little
- * degradation in the presence of more threads than cores,
- * aggressively adding new threads in such cases entails risk of
- * unwanted positive feedback control loops in which more threads
- * cause more dependent stalls (as well as delayed progress of
- * unblocked threads to the point that we know they are available)
- * leading to more situations requiring more threads, and so
- * on. This aspect of control can be seen as an (analytically
- * intractable) game with an opponent that may choose the worst
- * (for us) active thread to stall at any time. We take several
- * precautions to bound losses (and thus bound gains), mainly in
- * methods tryCompensate and awaitJoin.
+ * Compensation does not aim to keep exactly the target
+ * parallelism number of unblocked threads running at any given
+ * time. Some previous versions of this class employed immediate
+ * compensations for any blocked join. However, in practice, the
+ * vast majority of blockages are transient byproducts of GC and
+ * other JVM or OS activities that are made worse by replacement.
+ * Currently, compensation is attempted only after validating that
+ * all purportedly active threads are processing tasks by checking
+ * field WorkQueue.scanState, which eliminates most false
+ * positives. Also, compensation is bypassed (tolerating fewer
+ * threads) in the most common case in which it is rarely
+ * beneficial: when a worker with an empty queue (thus no
+ * continuation tasks) blocks on a join and there still remain
+ * enough threads to ensure liveness.
+ *
+ * The compensation mechanism may be bounded. Bounds for the
+ * commonPool (see commonMaxSpares) better enable JVMs to cope
+ * with programming errors and abuse before running out of
+ * resources to do so. In other cases, users may supply factories
+ * that limit thread construction. The effects of bounding in this
+ * pool (like all others) is imprecise. Total worker counts are
+ * decremented when threads deregister, not when they exit and
+ * resources are reclaimed by the JVM and OS. So the number of
+ * simultaneously live threads may transiently exceed bounds.
*
* Common Pool
* ===========
@@ -492,34 +620,52 @@
* never be used, we minimize initial construction overhead and
* footprint to the setup of about a dozen fields, with no nested
* allocation. Most bootstrapping occurs within method
- * fullExternalPush during the first submission to the pool.
+ * externalSubmit during the first submission to the pool.
*
* When external threads submit to the common pool, they can
- * perform subtask processing (see externalHelpJoin and related
- * methods). This caller-helps policy makes it sensible to set
- * common pool parallelism level to one (or more) less than the
- * total number of available cores, or even zero for pure
- * caller-runs. We do not need to record whether external
- * submissions are to the common pool -- if not, externalHelpJoin
- * returns quickly (at the most helping to signal some common pool
- * workers). These submitters would otherwise be blocked waiting
- * for completion, so the extra effort (with liberally sprinkled
- * task status checks) in inapplicable cases amounts to an odd
- * form of limited spin-wait before blocking in ForkJoinTask.join.
+ * perform subtask processing (see externalHelpComplete and
+ * related methods) upon joins. This caller-helps policy makes it
+ * sensible to set common pool parallelism level to one (or more)
+ * less than the total number of available cores, or even zero for
+ * pure caller-runs. We do not need to record whether external
+ * submissions are to the common pool -- if not, external help
+ * methods return quickly. These submitters would otherwise be
+ * blocked waiting for completion, so the extra effort (with
+ * liberally sprinkled task status checks) in inapplicable cases
+ * amounts to an odd form of limited spin-wait before blocking in
+ * ForkJoinTask.join.
*
* As a more appropriate default in managed environments, unless
* overridden by system properties, we use workers of subclass
* InnocuousForkJoinWorkerThread when there is a SecurityManager
* present. These workers have no permissions set, do not belong
* to any user-defined ThreadGroup, and erase all ThreadLocals
- * after executing any top-level task (see WorkQueue.runTask). The
- * associated mechanics (mainly in ForkJoinWorkerThread) may be
- * JVM-dependent and must access particular Thread class fields to
- * achieve this effect.
+ * after executing any top-level task (see WorkQueue.runTask).
+ * The associated mechanics (mainly in ForkJoinWorkerThread) may
+ * be JVM-dependent and must access particular Thread class fields
+ * to achieve this effect.
*
* Style notes
* ===========
*
+ * Memory ordering relies mainly on Unsafe intrinsics that carry
+ * the further responsibility of explicitly performing null- and
+ * bounds- checks otherwise carried out implicitly by JVMs. This
+ * can be awkward and ugly, but also reflects the need to control
+ * outcomes across the unusual cases that arise in very racy code
+ * with very few invariants. So these explicit checks would exist
+ * in some form anyway. All fields are read into locals before
+ * use, and null-checked if they are references. This is usually
+ * done in a "C"-like style of listing declarations at the heads
+ * of methods or blocks, and using inline assignments on first
+ * encounter. Array bounds-checks are usually performed by
+ * masking with array.length-1, which relies on the invariant that
+ * these arrays are created with positive lengths, which is itself
+ * paranoically checked. Nearly all explicit checks lead to
+ * bypass/return, not exception throws, because they may
+ * legitimately arise due to cancellation/revocation during
+ * shutdown.
+ *
* There is a lot of representation-level coupling among classes
* ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask. The
* fields of WorkQueue maintain data structures managed by
@@ -527,22 +673,13 @@
* trying to reduce this, since any associated future changes in
* representations will need to be accompanied by algorithmic
* changes anyway. Several methods intrinsically sprawl because
- * they must accumulate sets of consistent reads of volatiles held
- * in local variables. Methods signalWork() and scan() are the
- * main bottlenecks, so are especially heavily
- * micro-optimized/mangled. There are lots of inline assignments
- * (of form "while ((local = field) != 0)") which are usually the
- * simplest way to ensure the required read orderings (which are
- * sometimes critical). This leads to a "C"-like style of listing
- * declarations of these locals at the heads of methods or blocks.
- * There are several occurrences of the unusual "do {} while
- * (!cas...)" which is the simplest way to force an update of a
- * CAS'ed variable. There are also other coding oddities (including
- * several unnecessary-looking hoisted null checks) that help
- * some methods perform reasonably even when interpreted (not
- * compiled).
+ * they must accumulate sets of consistent reads of fields held in
+ * local variables. There are also other coding oddities
+ * (including several unnecessary-looking hoisted null checks)
+ * that help some methods perform reasonably even when interpreted
+ * (not compiled).
*
- * The order of declarations in this file is:
+ * The order of declarations in this file is (with a few exceptions):
* (1) Static utility functions
* (2) Nested (static) classes
* (3) Static fields
@@ -609,56 +746,37 @@
public final boolean exec() { return true; }
}
+ // Constants shared across ForkJoinPool and WorkQueue
+
+ // Bounds
+ static final int SMASK = 0xffff; // short bits == max index
+ static final int MAX_CAP = 0x7fff; // max #workers - 1
+ static final int EVENMASK = 0xfffe; // even short bits
+ static final int SQMASK = 0x007e; // max 64 (even) slots
+
+ // Masks and units for WorkQueue.scanState and ctl sp subfield
+ static final int SCANNING = 1; // false when running tasks
+ static final int INACTIVE = 1 << 31; // must be negative
+ static final int SS_SEQ = 1 << 16; // version count
+
+ // Mode bits for ForkJoinPool.config and WorkQueue.config
+ static final int MODE_MASK = 0xffff << 16; // top half of int
+ static final int LIFO_QUEUE = 0;
+ static final int FIFO_QUEUE = 1 << 16;
+ static final int SHARED_QUEUE = 1 << 31; // must be negative
+
/**
* Queues supporting work-stealing as well as external task
- * submission. See above for main rationale and algorithms.
- * Implementation relies heavily on "Unsafe" intrinsics
- * and selective use of "volatile":
- *
- * Field "base" is the index (mod array.length) of the least valid
- * queue slot, which is always the next position to steal (poll)
- * from if nonempty. Reads and writes require volatile orderings
- * but not CAS, because updates are only performed after slot
- * CASes.
- *
- * Field "top" is the index (mod array.length) of the next queue
- * slot to push to or pop from. It is written only by owner thread
- * for push, or under lock for external/shared push, and accessed
- * by other threads only after reading (volatile) base. Both top
- * and base are allowed to wrap around on overflow, but (top -
- * base) (or more commonly -(base - top) to force volatile read of
- * base before top) still estimates size. The lock ("qlock") is
- * forced to -1 on termination, causing all further lock attempts
- * to fail. (Note: we don't need CAS for termination state because
- * upon pool shutdown, all shared-queues will stop being used
- * anyway.) Nearly all lock bodies are set up so that exceptions
- * within lock bodies are "impossible" (modulo JVM errors that
- * would cause failure anyway.)
- *
- * The array slots are read and written using the emulation of
- * volatiles/atomics provided by Unsafe. Insertions must in
- * general use putOrderedObject as a form of releasing store to
- * ensure that all writes to the task object are ordered before
- * its publication in the queue. All removals entail a CAS to
- * null. The array is always a power of two. To ensure safety of
- * Unsafe array operations, all accesses perform explicit null
- * checks and implicit bounds checks via power-of-two masking.
- *
- * In addition to basic queuing support, this class contains
- * fields described elsewhere to control execution. It turns out
- * to work better memory-layout-wise to include them in this class
- * rather than a separate class.
- *
+ * submission. See above for descriptions and algorithms.
* Performance on most platforms is very sensitive to placement of
* instances of both WorkQueues and their arrays -- we absolutely
* do not want multiple WorkQueue instances or multiple queue
- * arrays sharing cache lines. (It would be best for queue objects
- * and their arrays to share, but there is nothing available to
- * help arrange that). The @Contended annotation alerts JVMs to
- * try to keep instances apart.
+ * arrays sharing cache lines. The @Contended annotation alerts
+ * JVMs to try to keep instances apart.
*/
@sun.misc.Contended
static final class WorkQueue {
+
/**
* Capacity of work-stealing queue array upon initialization.
* Must be a power of two; at least 4, but should be larger to
@@ -679,13 +797,13 @@
*/
static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
- volatile int eventCount; // encoded inactivation count; < 0 if inactive
- int nextWait; // encoded record of next event waiter
+ // Instance fields
+ volatile int scanState; // versioned, <0: inactive; odd:scanning
+ int stackPred; // pool stack (ctl) predecessor
int nsteals; // number of steals
- int hint; // steal index hint
- short poolIndex; // index of this queue in pool
- final short mode; // 0: lifo, > 0: fifo, < 0: shared
- volatile int qlock; // 1: locked, -1: terminate; else 0
+ int hint; // randomization and stealer index hint
+ int config; // pool index and mode
+ volatile int qlock; // 1: locked, < 0: terminate; else 0
volatile int base; // index of next slot for poll
int top; // index of next slot for push
ForkJoinTask<?>[] array; // the elements (initially unallocated)
@@ -693,19 +811,23 @@
final ForkJoinWorkerThread owner; // owning thread or null if shared
volatile Thread parker; // == owner during call to park; else null
volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin
- ForkJoinTask<?> currentSteal; // current non-local task being executed
+ volatile ForkJoinTask<?> currentSteal; // mainly used by helpStealer
- WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner, int mode,
- int seed) {
+ WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) {
this.pool = pool;
this.owner = owner;
- this.mode = (short)mode;
- this.hint = seed; // store initial seed for runWorker
// Place indices in the center of array (that is not yet allocated)
base = top = INITIAL_QUEUE_CAPACITY >>> 1;
}
/**
+ * Returns an exportable index (used by ForkJoinWorkerThread).
+ */
+ final int getPoolIndex() {
+ return (config & 0xffff) >>> 1; // ignore odd/even tag bit
+ }
+
+ /**
* Returns the approximate number of tasks in the queue.
*/
final int queueSize() {
@@ -719,12 +841,10 @@
* near-empty queue has at least one unclaimed task.
*/
final boolean isEmpty() {
- ForkJoinTask<?>[] a; int m, s;
- int n = base - (s = top);
- return (n >= 0 ||
- (n == -1 &&
- ((a = array) == null ||
- (m = a.length - 1) < 0 ||
+ ForkJoinTask<?>[] a; int n, m, s;
+ return ((n = base - (s = top)) >= 0 ||
+ (n == -1 && // possibly one task
+ ((a = array) == null || (m = a.length - 1) < 0 ||
U.getObject
(a, (long)((m & (s - 1)) << ASHIFT) + ABASE) == null)));
}
@@ -738,12 +858,15 @@
*/
final void push(ForkJoinTask<?> task) {
ForkJoinTask<?>[] a; ForkJoinPool p;
- int s = top, n;
+ int b = base, s = top, n;
if ((a = array) != null) { // ignore if queue removed
- int m = a.length - 1;
+ int m = a.length - 1; // fenced write for task visibility
U.putOrderedObject(a, ((m & s) << ASHIFT) + ABASE, task);
- if ((n = (top = s + 1) - base) <= 2)
- (p = pool).signalWork(p.workQueues, this);
+ U.putOrderedInt(this, QTOP, s + 1);
+ if ((n = s - b) <= 1) {
+ if ((p = pool) != null)
+ p.signalWork(p.workQueues, this);
+ }
else if (n >= m)
growArray();
}
@@ -764,7 +887,7 @@
if (oldA != null && (oldMask = oldA.length - 1) >= 0 &&
(t = top) - (b = base) > 0) {
int mask = size - 1;
- do {
+ do { // emulate poll from old array, push to new array
ForkJoinTask<?> x;
int oldj = ((b & oldMask) << ASHIFT) + ABASE;
int j = ((b & mask) << ASHIFT) + ABASE;
@@ -789,7 +912,7 @@
if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null)
break;
if (U.compareAndSwapObject(a, j, t, null)) {
- top = s;
+ U.putOrderedInt(this, QTOP, s);
return t;
}
}
@@ -800,7 +923,7 @@
/**
* Takes a task in FIFO order if b is base of queue and a task
* can be claimed without contention. Specialized versions
- * appear in ForkJoinPool methods scan and tryHelpStealer.
+ * appear in ForkJoinPool methods scan and helpStealer.
*/
final ForkJoinTask<?> pollAt(int b) {
ForkJoinTask<?> t; ForkJoinTask<?>[] a;
@@ -808,7 +931,7 @@
int j = (((a.length - 1) & b) << ASHIFT) + ABASE;
if ((t = (ForkJoinTask<?>)U.getObjectVolatile(a, j)) != null &&
base == b && U.compareAndSwapObject(a, j, t, null)) {
- U.putOrderedInt(this, QBASE, b + 1);
+ base = b + 1;
return t;
}
}
@@ -823,16 +946,15 @@
while ((b = base) - top < 0 && (a = array) != null) {
int j = (((a.length - 1) & b) << ASHIFT) + ABASE;
t = (ForkJoinTask<?>)U.getObjectVolatile(a, j);
- if (t != null) {
- if (U.compareAndSwapObject(a, j, t, null)) {
- U.putOrderedInt(this, QBASE, b + 1);
- return t;
+ if (base == b) {
+ if (t != null) {
+ if (U.compareAndSwapObject(a, j, t, null)) {
+ base = b + 1;
+ return t;
+ }
}
- }
- else if (base == b) {
- if (b + 1 == top)
+ else if (b + 1 == top) // now empty
break;
- Thread.yield(); // wait for lagging update (very rare)
}
}
return null;
@@ -842,7 +964,7 @@
* Takes next task, if one exists, in order specified by mode.
*/
final ForkJoinTask<?> nextLocalTask() {
- return mode == 0 ? pop() : poll();
+ return (config & FIFO_QUEUE) == 0 ? pop() : poll();
}
/**
@@ -852,7 +974,7 @@
ForkJoinTask<?>[] a = array; int m;
if (a == null || (m = a.length - 1) < 0)
return null;
- int i = mode == 0 ? top - 1 : base;
+ int i = (config & FIFO_QUEUE) == 0 ? top - 1 : base;
int j = ((i & m) << ASHIFT) + ABASE;
return (ForkJoinTask<?>)U.getObjectVolatile(a, j);
}
@@ -860,13 +982,13 @@
/**
* Pops the given task only if it is at the current top.
* (A shared version is available only via FJP.tryExternalUnpush)
- */
+ */
final boolean tryUnpush(ForkJoinTask<?> t) {
ForkJoinTask<?>[] a; int s;
if ((a = array) != null && (s = top) != base &&
U.compareAndSwapObject
(a, (((a.length - 1) & --s) << ASHIFT) + ABASE, t, null)) {
- top = s;
+ U.putOrderedInt(this, QTOP, s);
return true;
}
return false;
@@ -876,9 +998,16 @@
* Removes and cancels all known tasks, ignoring any exceptions.
*/
final void cancelAll() {
- ForkJoinTask.cancelIgnoringExceptions(currentJoin);
- ForkJoinTask.cancelIgnoringExceptions(currentSteal);
- for (ForkJoinTask<?> t; (t = poll()) != null; )
+ ForkJoinTask<?> t;
+ if ((t = currentJoin) != null) {
+ currentJoin = null;
+ ForkJoinTask.cancelIgnoringExceptions(t);
+ }
+ if ((t = currentSteal) != null) {
+ currentSteal = null;
+ ForkJoinTask.cancelIgnoringExceptions(t);
+ }
+ while ((t = poll()) != null)
ForkJoinTask.cancelIgnoringExceptions(t);
}
@@ -893,167 +1022,186 @@
}
/**
- * Executes a top-level task and any local tasks remaining
- * after execution.
+ * Removes and executes all local tasks. If LIFO, invokes
+ * pollAndExecAll. Otherwise implements a specialized pop loop
+ * to exec until empty.
*/
- final void runTask(ForkJoinTask<?> task) {
- if ((currentSteal = task) != null) {
- ForkJoinWorkerThread thread;
- task.doExec();
- ForkJoinTask<?>[] a = array;
- int md = mode;
- ++nsteals;
- currentSteal = null;
- if (md != 0)
- pollAndExecAll();
- else if (a != null) {
- int s, m = a.length - 1;
- ForkJoinTask<?> t;
- while ((s = top - 1) - base >= 0 &&
- (t = (ForkJoinTask<?>)U.getAndSetObject
- (a, ((m & s) << ASHIFT) + ABASE, null)) != null) {
- top = s;
+ final void execLocalTasks() {
+ int b = base, m, s;
+ ForkJoinTask<?>[] a = array;
+ if (b - (s = top - 1) <= 0 && a != null &&
+ (m = a.length - 1) >= 0) {
+ if ((config & FIFO_QUEUE) == 0) {
+ for (ForkJoinTask<?> t;;) {
+ if ((t = (ForkJoinTask<?>)U.getAndSetObject
+ (a, ((m & s) << ASHIFT) + ABASE, null)) == null)
+ break;
+ U.putOrderedInt(this, QTOP, s);
t.doExec();
+ if (base - (s = top - 1) > 0)
+ break;
}
}
- if ((thread = owner) != null) // no need to do in finally clause
+ else
+ pollAndExecAll();
+ }
+ }
+
+ /**
+ * Executes the given task and any remaining local tasks.
+ */
+ final void runTask(ForkJoinTask<?> task) {
+ if (task != null) {
+ scanState &= ~SCANNING; // mark as busy
+ (currentSteal = task).doExec();
+ U.putOrderedObject(this, QCURRENTSTEAL, null); // release for GC
+ execLocalTasks();
+ ForkJoinWorkerThread thread = owner;
+ if (++nsteals < 0) // collect on overflow
+ transferStealCount(pool);
+ scanState |= SCANNING;
+ if (thread != null)
thread.afterTopLevelExec();
}
}
/**
+ * Adds steal count to pool stealCounter if it exists, and resets.
+ */
+ final void transferStealCount(ForkJoinPool p) {
+ AtomicLong sc;
+ if (p != null && (sc = p.stealCounter) != null) {
+ int s = nsteals;
+ nsteals = 0; // if negative, correct for overflow
+ sc.getAndAdd((long)(s < 0 ? Integer.MAX_VALUE : s));
+ }
+ }
+
+ /**
* If present, removes from queue and executes the given task,
- * or any other cancelled task. Returns (true) on any CAS
- * or consistency check failure so caller can retry.
+ * or any other cancelled task. Used only by awaitJoin.
*
- * @return false if no progress can be made, else true
+ * @return true if queue empty and task not known to be done
*/
final boolean tryRemoveAndExec(ForkJoinTask<?> task) {
- boolean stat;
ForkJoinTask<?>[] a; int m, s, b, n;
- if (task != null && (a = array) != null && (m = a.length - 1) >= 0 &&
- (n = (s = top) - (b = base)) > 0) {
- boolean removed = false, empty = true;
- stat = true;
- for (ForkJoinTask<?> t;;) { // traverse from s to b
- long j = ((--s & m) << ASHIFT) + ABASE;
- t = (ForkJoinTask<?>)U.getObject(a, j);
- if (t == null) // inconsistent length
- break;
- else if (t == task) {
- if (s + 1 == top) { // pop
- if (!U.compareAndSwapObject(a, j, task, null))
- break;
- top = s;
- removed = true;
+ if ((a = array) != null && (m = a.length - 1) >= 0 &&
+ task != null) {
+ while ((n = (s = top) - (b = base)) > 0) {
+ for (ForkJoinTask<?> t;;) { // traverse from s to b
+ long j = ((--s & m) << ASHIFT) + ABASE;
+ if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null)
+ return s + 1 == top; // shorter than expected
+ else if (t == task) {
+ boolean removed = false;
+ if (s + 1 == top) { // pop
+ if (U.compareAndSwapObject(a, j, task, null)) {
+ U.putOrderedInt(this, QTOP, s);
+ removed = true;
+ }
+ }
+ else if (base == b) // replace with proxy
+ removed = U.compareAndSwapObject(
+ a, j, task, new EmptyTask());
+ if (removed)
+ task.doExec();
+ break;
}
- else if (base == b) // replace with proxy
- removed = U.compareAndSwapObject(a, j, task,
- new EmptyTask());
- break;
+ else if (t.status < 0 && s + 1 == top) {
+ if (U.compareAndSwapObject(a, j, t, null))
+ U.putOrderedInt(this, QTOP, s);
+ break; // was cancelled
+ }
+ if (--n == 0)
+ return false;
}
- else if (t.status >= 0)
- empty = false;
- else if (s + 1 == top) { // pop and throw away
- if (U.compareAndSwapObject(a, j, t, null))
- top = s;
- break;
- }
- if (--n == 0) {
- if (!empty && base == b)
- stat = false;
- break;
- }
+ if (task.status < 0)
+ return false;
}
- if (removed)
- task.doExec();
}
- else
- stat = false;
- return stat;
+ return true;
}
/**
- * Tries to poll for and execute the given task or any other
- * task in its CountedCompleter computation.
+ * Pops task if in the same CC computation as the given task,
+ * in either shared or owned mode. Used only by helpComplete.
*/
- final boolean pollAndExecCC(CountedCompleter<?> root) {
- ForkJoinTask<?>[] a; int b; Object o; CountedCompleter<?> t, r;
- if ((b = base) - top < 0 && (a = array) != null) {
+ final CountedCompleter<?> popCC(CountedCompleter<?> task, int mode) {
+ int s; ForkJoinTask<?>[] a; Object o;
+ if (base - (s = top) < 0 && (a = array) != null) {
+ long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
+ if ((o = U.getObjectVolatile(a, j)) != null &&
+ (o instanceof CountedCompleter)) {
+ CountedCompleter<?> t = (CountedCompleter<?>)o;
+ for (CountedCompleter<?> r = t;;) {
+ if (r == task) {
+ if (mode < 0) { // must lock
+ if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+ if (top == s && array == a &&
+ U.compareAndSwapObject(a, j, t, null)) {
+ U.putOrderedInt(this, QTOP, s - 1);
+ U.putOrderedInt(this, QLOCK, 0);
+ return t;
+ }
+ U.compareAndSwapInt(this, QLOCK, 1, 0);
+ }
+ }
+ else if (U.compareAndSwapObject(a, j, t, null)) {
+ U.putOrderedInt(this, QTOP, s - 1);
+ return t;
+ }
+ break;
+ }
+ else if ((r = r.completer) == null) // try parent
+ break;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Steals and runs a task in the same CC computation as the
+ * given task if one exists and can be taken without
+ * contention. Otherwise returns a checksum/control value for
+ * use by method helpComplete.
+ *
+ * @return 1 if successful, 2 if retryable (lost to another
+ * stealer), -1 if non-empty but no matching task found, else
+ * the base index, forced negative.
+ */
+ final int pollAndExecCC(CountedCompleter<?> task) {
+ int b, h; ForkJoinTask<?>[] a; Object o;
+ if ((b = base) - top >= 0 || (a = array) == null)
+ h = b | Integer.MIN_VALUE; // to sense movement on re-poll
+ else {
long j = (((a.length - 1) & b) << ASHIFT) + ABASE;
if ((o = U.getObjectVolatile(a, j)) == null)
- return true; // retry
- if (o instanceof CountedCompleter) {
- for (t = (CountedCompleter<?>)o, r = t;;) {
- if (r == root) {
+ h = 2; // retryable
+ else if (!(o instanceof CountedCompleter))
+ h = -1; // unmatchable
+ else {
+ CountedCompleter<?> t = (CountedCompleter<?>)o;
+ for (CountedCompleter<?> r = t;;) {
+ if (r == task) {
if (base == b &&
U.compareAndSwapObject(a, j, t, null)) {
- U.putOrderedInt(this, QBASE, b + 1);
+ base = b + 1;
t.doExec();
+ h = 1; // success
}
- return true;
- }
- else if ((r = r.completer) == null)
- break; // not part of root computation
- }
- }
- }
- return false;
- }
-
- /**
- * Tries to pop and execute the given task or any other task
- * in its CountedCompleter computation.
- */
- final boolean externalPopAndExecCC(CountedCompleter<?> root) {
- ForkJoinTask<?>[] a; int s; Object o; CountedCompleter<?> t, r;
- if (base - (s = top) < 0 && (a = array) != null) {
- long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
- if ((o = U.getObject(a, j)) instanceof CountedCompleter) {
- for (t = (CountedCompleter<?>)o, r = t;;) {
- if (r == root) {
- if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
- if (top == s && array == a &&
- U.compareAndSwapObject(a, j, t, null)) {
- top = s - 1;
- qlock = 0;
- t.doExec();
- }
- else
- qlock = 0;
- }
- return true;
- }
- else if ((r = r.completer) == null)
+ else
+ h = 2; // lost CAS
break;
- }
- }
- }
- return false;
- }
-
- /**
- * Internal version
- */
- final boolean internalPopAndExecCC(CountedCompleter<?> root) {
- ForkJoinTask<?>[] a; int s; Object o; CountedCompleter<?> t, r;
- if (base - (s = top) < 0 && (a = array) != null) {
- long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
- if ((o = U.getObject(a, j)) instanceof CountedCompleter) {
- for (t = (CountedCompleter<?>)o, r = t;;) {
- if (r == root) {
- if (U.compareAndSwapObject(a, j, t, null)) {
- top = s - 1;
- t.doExec();
- }
- return true;
}
- else if ((r = r.completer) == null)
+ else if ((r = r.completer) == null) {
+ h = -1; // unmatched
break;
+ }
}
}
}
- return false;
+ return h;
}
/**
@@ -1061,28 +1209,31 @@
*/
final boolean isApparentlyUnblocked() {
Thread wt; Thread.State s;
- return (eventCount >= 0 &&
+ return (scanState >= 0 &&
(wt = owner) != null &&
(s = wt.getState()) != Thread.State.BLOCKED &&
s != Thread.State.WAITING &&
s != Thread.State.TIMED_WAITING);
}
- // Unsafe mechanics
+ // Unsafe mechanics. Note that some are (and must be) the same as in FJP
private static final sun.misc.Unsafe U;
- private static final long QBASE;
+ private static final int ABASE;
+ private static final int ASHIFT;
+ private static final long QTOP;
private static final long QLOCK;
- private static final int ABASE;
- private static final int ASHIFT;
+ private static final long QCURRENTSTEAL;
static {
try {
U = sun.misc.Unsafe.getUnsafe();
- Class<?> k = WorkQueue.class;
+ Class<?> wk = WorkQueue.class;
Class<?> ak = ForkJoinTask[].class;
- QBASE = U.objectFieldOffset
- (k.getDeclaredField("base"));
+ QTOP = U.objectFieldOffset
+ (wk.getDeclaredField("top"));
QLOCK = U.objectFieldOffset
- (k.getDeclaredField("qlock"));
+ (wk.getDeclaredField("qlock"));
+ QCURRENTSTEAL = U.objectFieldOffset
+ (wk.getDeclaredField("currentSteal"));
ABASE = U.arrayBaseOffset(ak);
int scale = U.arrayIndexScale(ak);
if ((scale & (scale - 1)) != 0)
@@ -1126,6 +1277,11 @@
static final int commonParallelism;
/**
+ * Limit on spare thread construction in tryCompensate.
+ */
+ private static int commonMaxSpares;
+
+ /**
* Sequence number for creating workerNamePrefix.
*/
private static int poolNumberSequence;
@@ -1138,7 +1294,7 @@
return ++poolNumberSequence;
}
- // static constants
+ // static configuration constants
/**
* Initial timeout value (in nanoseconds) for the thread
@@ -1148,27 +1304,32 @@
* aggressive shrinkage during most transient stalls (long GCs
* etc).
*/
- private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec
-
- /**
- * Timeout value when there are more threads than parallelism level
- */
- private static final long FAST_IDLE_TIMEOUT = 200L * 1000L * 1000L;
+ private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec
/**
* Tolerance for idle timeouts, to cope with timer undershoots
*/
- private static final long TIMEOUT_SLOP = 2000000L;
+ private static final long TIMEOUT_SLOP = 20L * 1000L * 1000L; // 20ms
/**
- * The maximum stolen->joining link depth allowed in method
- * tryHelpStealer. Must be a power of two. Depths for legitimate
- * chains are unbounded, but we use a fixed constant to avoid
- * (otherwise unchecked) cycles and to bound staleness of
- * traversal parameters at the expense of sometimes blocking when
- * we could be helping.
+ * The initial value for commonMaxSpares during static
+ * initialization. The value is far in excess of normal
+ * requirements, but also far short of MAX_CAP and typical
+ * OS thread limits, so allows JVMs to catch misuse/abuse
+ * before running out of resources needed to do so.
*/
- private static final int MAX_HELP = 64;
+ private static final int DEFAULT_COMMON_MAX_SPARES = 256;
+
+ /**
+ * Number of times to spin-wait before blocking. The spins (in
+ * awaitRunStateLock and awaitWork) currently use randomized
+ * spins. If/when MWAIT-like intrinsics becomes available, they
+ * may allow quieter spinning. The value of SPINS must be a power
+ * of two, at least 4. The current value causes spinning for a
+ * small fraction of typical context-switch times, well worthwhile
+ * given the typical likelihoods that blocking is not necessary.
+ */
+ private static final int SPINS = 1 << 11;
/**
* Increment for seed generators. See class ThreadLocal for
@@ -1177,209 +1338,212 @@
private static final int SEED_INCREMENT = 0x9e3779b9;
/*
- * Bits and masks for control variables
+ * Bits and masks for field ctl, packed with 4 16 bit subfields:
+ * AC: Number of active running workers minus target parallelism
+ * TC: Number of total workers minus target parallelism
+ * SS: version count and status of top waiting thread
+ * ID: poolIndex of top of Treiber stack of waiters
*
- * Field ctl is a long packed with:
- * AC: Number of active running workers minus target parallelism (16 bits)
- * TC: Number of total workers minus target parallelism (16 bits)
- * ST: true if pool is terminating (1 bit)
- * EC: the wait count of top waiting thread (15 bits)
- * ID: poolIndex of top of Treiber stack of waiters (16 bits)
+ * When convenient, we can extract the lower 32 stack top bits
+ * (including version bits) as sp=(int)ctl. The offsets of counts
+ * by the target parallelism and the positionings of fields makes
+ * it possible to perform the most common checks via sign tests of
+ * fields: When ac is negative, there are not enough active
+ * workers, when tc is negative, there are not enough total
+ * workers. When sp is non-zero, there are waiting workers. To
+ * deal with possibly negative fields, we use casts in and out of
+ * "short" and/or signed shifts to maintain signedness.
*
- * When convenient, we can extract the upper 32 bits of counts and
- * the lower 32 bits of queue state, u = (int)(ctl >>> 32) and e =
- * (int)ctl. The ec field is never accessed alone, but always
- * together with id and st. The offsets of counts by the target
- * parallelism and the positionings of fields makes it possible to
- * perform the most common checks via sign tests of fields: When
- * ac is negative, there are not enough active workers, when tc is
- * negative, there are not enough total workers, and when e is
- * negative, the pool is terminating. To deal with these possibly
- * negative fields, we use casts in and out of "short" and/or
- * signed shifts to maintain signedness.
- *
- * When a thread is queued (inactivated), its eventCount field is
- * set negative, which is the only way to tell if a worker is
- * prevented from executing tasks, even though it must continue to
- * scan for them to avoid queuing races. Note however that
- * eventCount updates lag releases so usage requires care.
- *
- * Field plock is an int packed with:
- * SHUTDOWN: true if shutdown is enabled (1 bit)
- * SEQ: a sequence lock, with PL_LOCK bit set if locked (30 bits)
- * SIGNAL: set when threads may be waiting on the lock (1 bit)
- *
- * The sequence number enables simple consistency checks:
- * Staleness of read-only operations on the workQueues array can
- * be checked by comparing plock before vs after the reads.
+ * Because it occupies uppermost bits, we can add one active count
+ * using getAndAddLong of AC_UNIT, rather than CAS, when returning
+ * from a blocked join. Other updates entail multiple subfields
+ * and masking, requiring CAS.
*/
- // bit positions/shifts for fields
+ // Lower and upper word masks
+ private static final long SP_MASK = 0xffffffffL;
+ private static final long UC_MASK = ~SP_MASK;
+
+ // Active counts
private static final int AC_SHIFT = 48;
+ private static final long AC_UNIT = 0x0001L << AC_SHIFT;
+ private static final long AC_MASK = 0xffffL << AC_SHIFT;
+
+ // Total counts
private static final int TC_SHIFT = 32;
- private static final int ST_SHIFT = 31;
- private static final int EC_SHIFT = 16;
+ private static final long TC_UNIT = 0x0001L << TC_SHIFT;
+ private static final long TC_MASK = 0xffffL << TC_SHIFT;
+ private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
- // bounds
- private static final int SMASK = 0xffff; // short bits
- private static final int MAX_CAP = 0x7fff; // max #workers - 1
- private static final int EVENMASK = 0xfffe; // even short bits
- private static final int SQMASK = 0x007e; // max 64 (even) slots
- private static final int SHORT_SIGN = 1 << 15;
- private static final int INT_SIGN = 1 << 31;
-
- // masks
- private static final long STOP_BIT = 0x0001L << ST_SHIFT;
- private static final long AC_MASK = ((long)SMASK) << AC_SHIFT;
- private static final long TC_MASK = ((long)SMASK) << TC_SHIFT;
-
- // units for incrementing and decrementing
- private static final long TC_UNIT = 1L << TC_SHIFT;
- private static final long AC_UNIT = 1L << AC_SHIFT;
-
- // masks and units for dealing with u = (int)(ctl >>> 32)
- private static final int UAC_SHIFT = AC_SHIFT - 32;
- private static final int UTC_SHIFT = TC_SHIFT - 32;
- private static final int UAC_MASK = SMASK << UAC_SHIFT;
- private static final int UTC_MASK = SMASK << UTC_SHIFT;
- private static final int UAC_UNIT = 1 << UAC_SHIFT;
- private static final int UTC_UNIT = 1 << UTC_SHIFT;
-
- // masks and units for dealing with e = (int)ctl
- private static final int E_MASK = 0x7fffffff; // no STOP_BIT
- private static final int E_SEQ = 1 << EC_SHIFT;
-
- // plock bits
- private static final int SHUTDOWN = 1 << 31;
- private static final int PL_LOCK = 2;
- private static final int PL_SIGNAL = 1;
- private static final int PL_SPINS = 1 << 8;
-
- // access mode for WorkQueue
- static final int LIFO_QUEUE = 0;
- static final int FIFO_QUEUE = 1;
- static final int SHARED_QUEUE = -1;
+ // runState bits: SHUTDOWN must be negative, others arbitrary powers of two
+ private static final int RSLOCK = 1;
+ private static final int RSIGNAL = 1 << 1;
+ private static final int STARTED = 1 << 2;
+ private static final int STOP = 1 << 29;
+ private static final int TERMINATED = 1 << 30;
+ private static final int SHUTDOWN = 1 << 31;
// Instance fields
- volatile long stealCount; // collects worker counts
- volatile long ctl; // main pool control
- volatile int plock; // shutdown status and seqLock
- volatile int indexSeed; // worker/submitter index seed
- final short parallelism; // parallelism level
- final short mode; // LIFO/FIFO
- WorkQueue[] workQueues; // main registry
+ volatile long ctl; // main pool control
+ volatile int runState; // lockable status
+ final int config; // parallelism, mode
+ int indexSeed; // to generate worker index
+ volatile WorkQueue[] workQueues; // main registry
final ForkJoinWorkerThreadFactory factory;
- final UncaughtExceptionHandler ueh; // per-worker UEH
- final String workerNamePrefix; // to create worker name string
+ final UncaughtExceptionHandler ueh; // per-worker UEH
+ final String workerNamePrefix; // to create worker name string
+ volatile AtomicLong stealCounter; // also used as sync monitor
/**
- * Acquires the plock lock to protect worker array and related
- * updates. This method is called only if an initial CAS on plock
- * fails. This acts as a spinlock for normal cases, but falls back
- * to builtin monitor to block when (rarely) needed. This would be
- * a terrible idea for a highly contended lock, but works fine as
- * a more conservative alternative to a pure spinlock.
+ * Acquires the runState lock; returns current (locked) runState.
*/
- private int acquirePlock() {
- int spins = PL_SPINS, ps, nps;
- for (;;) {
- if (((ps = plock) & PL_LOCK) == 0 &&
- U.compareAndSwapInt(this, PLOCK, ps, nps = ps + PL_LOCK))
- return nps;
- else if (spins >= 0) {
- if (ThreadLocalRandom.nextSecondarySeed() >= 0)
+ private int lockRunState() {
+ int rs;
+ return ((((rs = runState) & RSLOCK) != 0 ||
+ !U.compareAndSwapInt(this, RUNSTATE, rs, rs |= RSLOCK)) ?
+ awaitRunStateLock() : rs);
+ }
+
+ /**
+ * Spins and/or blocks until runstate lock is available. See
+ * above for explanation.
+ */
+ private int awaitRunStateLock() {
+ Object lock;
+ boolean wasInterrupted = false;
+ for (int spins = SPINS, r = 0, rs, ns;;) {
+ if (((rs = runState) & RSLOCK) == 0) {
+ if (U.compareAndSwapInt(this, RUNSTATE, rs, ns = rs | RSLOCK)) {
+ if (wasInterrupted) {
+ try {
+ Thread.currentThread().interrupt();
+ } catch (SecurityException ignore) {
+ }
+ }
+ return ns;
+ }
+ }
+ else if (r == 0)
+ r = ThreadLocalRandom.nextSecondarySeed();
+ else if (spins > 0) {
+ r ^= r << 6; r ^= r >>> 21; r ^= r << 7; // xorshift
+ if (r >= 0)
--spins;
}
- else if (U.compareAndSwapInt(this, PLOCK, ps, ps | PL_SIGNAL)) {
- synchronized (this) {
- if ((plock & PL_SIGNAL) != 0) {
+ else if ((rs & STARTED) == 0 || (lock = stealCounter) == null)
+ Thread.yield(); // initialization race
+ else if (U.compareAndSwapInt(this, RUNSTATE, rs, rs | RSIGNAL)) {
+ synchronized (lock) {
+ if ((runState & RSIGNAL) != 0) {
try {
- wait();
+ lock.wait();
} catch (InterruptedException ie) {
- try {
- Thread.currentThread().interrupt();
- } catch (SecurityException ignore) {
- }
+ if (!(Thread.currentThread() instanceof
+ ForkJoinWorkerThread))
+ wasInterrupted = true;
}
}
else
- notifyAll();
+ lock.notifyAll();
}
}
}
}
/**
- * Unlocks and signals any thread waiting for plock. Called only
- * when CAS of seq value for unlock fails.
+ * Unlocks and sets runState to newRunState.
+ *
+ * @param oldRunState a value returned from lockRunState
+ * @param newRunState the next value (must have lock bit clear).
*/
- private void releasePlock(int ps) {
- plock = ps;
- synchronized (this) { notifyAll(); }
- }
-
- /**
- * Tries to create and start one worker if fewer than target
- * parallelism level exist. Adjusts counts etc on failure.
- */
- private void tryAddWorker() {
- long c; int u, e;
- while ((u = (int)((c = ctl) >>> 32)) < 0 &&
- (u & SHORT_SIGN) != 0 && (e = (int)c) >= 0) {
- long nc = ((long)(((u + UTC_UNIT) & UTC_MASK) |
- ((u + UAC_UNIT) & UAC_MASK)) << 32) | (long)e;
- if (U.compareAndSwapLong(this, CTL, c, nc)) {
- ForkJoinWorkerThreadFactory fac;
- Throwable ex = null;
- ForkJoinWorkerThread wt = null;
- try {
- if ((fac = factory) != null &&
- (wt = fac.newThread(this)) != null) {
- wt.start();
- break;
- }
- } catch (Throwable rex) {
- ex = rex;
- }
- deregisterWorker(wt, ex);
- break;
- }
+ private void unlockRunState(int oldRunState, int newRunState) {
+ if (!U.compareAndSwapInt(this, RUNSTATE, oldRunState, newRunState)) {
+ Object lock = stealCounter;
+ runState = newRunState; // clears RSIGNAL bit
+ if (lock != null)
+ synchronized (lock) { lock.notifyAll(); }
}
}
- // Registering and deregistering workers
+ // Creating, registering and deregistering workers
/**
- * Callback from ForkJoinWorkerThread to establish and record its
- * WorkQueue. To avoid scanning bias due to packing entries in
- * front of the workQueues array, we treat the array as a simple
- * power-of-two hash table using per-thread seed as hash,
- * expanding as needed.
+ * Tries to construct and start one worker. Assumes that total
+ * count has already been incremented as a reservation. Invokes
+ * deregisterWorker on any failure.
+ *
+ * @return true if successful
+ */
+ private boolean createWorker() {
+ ForkJoinWorkerThreadFactory fac = factory;
+ Throwable ex = null;
+ ForkJoinWorkerThread wt = null;
+ try {
+ if (fac != null && (wt = fac.newThread(this)) != null) {
+ wt.start();
+ return true;
+ }
+ } catch (Throwable rex) {
+ ex = rex;
+ }
+ deregisterWorker(wt, ex);
+ return false;
+ }
+
+ /**
+ * Tries to add one worker, incrementing ctl counts before doing
+ * so, relying on createWorker to back out on failure.
+ *
+ * @param c incoming ctl value, with total count negative and no
+ * idle workers. On CAS failure, c is refreshed and retried if
+ * this holds (otherwise, a new worker is not needed).
+ */
+ private void tryAddWorker(long c) {
+ boolean add = false;
+ do {
+ long nc = ((AC_MASK & (c + AC_UNIT)) |
+ (TC_MASK & (c + TC_UNIT)));
+ if (ctl == c) {
+ int rs, stop; // check if terminating
+ if ((stop = (rs = lockRunState()) & STOP) == 0)
+ add = U.compareAndSwapLong(this, CTL, c, nc);
+ unlockRunState(rs, rs & ~RSLOCK);
+ if (stop != 0)
+ break;
+ if (add) {
+ createWorker();
+ break;
+ }
+ }
+ } while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
+ }
+
+ /**
+ * Callback from ForkJoinWorkerThread constructor to establish and
+ * record its WorkQueue.
*
* @param wt the worker thread
* @return the worker's queue
*/
final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
- UncaughtExceptionHandler handler; WorkQueue[] ws; int s, ps;
- wt.setDaemon(true);
+ UncaughtExceptionHandler handler;
+ wt.setDaemon(true); // configure thread
if ((handler = ueh) != null)
wt.setUncaughtExceptionHandler(handler);
- do {} while (!U.compareAndSwapInt(this, INDEXSEED, s = indexSeed,
- s += SEED_INCREMENT) ||
- s == 0); // skip 0
- WorkQueue w = new WorkQueue(this, wt, mode, s);
- if (((ps = plock) & PL_LOCK) != 0 ||
- !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
- ps = acquirePlock();
- int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
+ WorkQueue w = new WorkQueue(this, wt);
+ int i = 0; // assign a pool index
+ int mode = config & MODE_MASK;
+ int rs = lockRunState();
try {
- if ((ws = workQueues) != null) { // skip if shutting down
- int n = ws.length, m = n - 1;
- int r = (s << 1) | 1; // use odd-numbered indices
- if (ws[r &= m] != null) { // collision
- int probes = 0; // step by approx half size
+ WorkQueue[] ws; int n; // skip if no array
+ if ((ws = workQueues) != null && (n = ws.length) > 0) {
+ int s = indexSeed += SEED_INCREMENT; // unlikely to collide
+ int m = n - 1;
+ i = ((s << 1) | 1) & m; // odd-numbered indices
+ if (ws[i] != null) { // collision
+ int probes = 0; // step by approx half n
int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
- while (ws[r = (r + step) & m] != null) {
+ while (ws[i = (i + step) & m] != null) {
if (++probes >= n) {
workQueues = ws = Arrays.copyOf(ws, n <<= 1);
m = n - 1;
@@ -1387,15 +1551,15 @@
}
}
}
- w.poolIndex = (short)r;
- w.eventCount = r; // volatile write orders
- ws[r] = w;
+ w.hint = s; // use as random seed
+ w.config = i | mode;
+ w.scanState = i; // publication fence
+ ws[i] = w;
}
} finally {
- if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
- releasePlock(nps);
+ unlockRunState(rs, rs & ~RSLOCK);
}
- wt.setName(workerNamePrefix.concat(Integer.toString(w.poolIndex >>> 1)));
+ wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
return w;
}
@@ -1411,384 +1575,322 @@
final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
WorkQueue w = null;
if (wt != null && (w = wt.workQueue) != null) {
- int ps;
- w.qlock = -1; // ensure set
- U.getAndAddLong(this, STEALCOUNT, w.nsteals); // collect steals
- if (((ps = plock) & PL_LOCK) != 0 ||
- !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
- ps = acquirePlock();
- int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
- try {
- int idx = w.poolIndex;
- WorkQueue[] ws = workQueues;
- if (ws != null && idx >= 0 && idx < ws.length && ws[idx] == w)
- ws[idx] = null;
- } finally {
- if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
- releasePlock(nps);
- }
+ WorkQueue[] ws; // remove index from array
+ int idx = w.config & SMASK;
+ int rs = lockRunState();
+ if ((ws = workQueues) != null && ws.length > idx && ws[idx] == w)
+ ws[idx] = null;
+ unlockRunState(rs, rs & ~RSLOCK);
}
-
- long c; // adjust ctl counts
+ long c; // decrement counts
do {} while (!U.compareAndSwapLong
- (this, CTL, c = ctl, (((c - AC_UNIT) & AC_MASK) |
- ((c - TC_UNIT) & TC_MASK) |
- (c & ~(AC_MASK|TC_MASK)))));
-
- if (!tryTerminate(false, false) && w != null && w.array != null) {
- w.cancelAll(); // cancel remaining tasks
- WorkQueue[] ws; WorkQueue v; Thread p; int u, i, e;
- while ((u = (int)((c = ctl) >>> 32)) < 0 && (e = (int)c) >= 0) {
- if (e > 0) { // activate or create replacement
- if ((ws = workQueues) == null ||
- (i = e & SMASK) >= ws.length ||
- (v = ws[i]) == null)
- break;
- long nc = (((long)(v.nextWait & E_MASK)) |
- ((long)(u + UAC_UNIT) << 32));
- if (v.eventCount != (e | INT_SIGN))
- break;
- if (U.compareAndSwapLong(this, CTL, c, nc)) {
- v.eventCount = (e + E_SEQ) & E_MASK;
- if ((p = v.parker) != null)
- U.unpark(p);
- break;
- }
- }
- else {
- if ((short)u < 0)
- tryAddWorker();
- break;
- }
- }
+ (this, CTL, c = ctl, ((AC_MASK & (c - AC_UNIT)) |
+ (TC_MASK & (c - TC_UNIT)) |
+ (SP_MASK & c))));
+ if (w != null) {
+ w.qlock = -1; // ensure set
+ w.transferStealCount(this);
+ w.cancelAll(); // cancel remaining tasks
}
- if (ex == null) // help clean refs on way out
+ for (;;) { // possibly replace
+ WorkQueue[] ws; int m, sp;
+ if (tryTerminate(false, false) || w == null || w.array == null ||
+ (runState & STOP) != 0 || (ws = workQueues) == null ||
+ (m = ws.length - 1) < 0) // already terminating
+ break;
+ if ((sp = (int)(c = ctl)) != 0) { // wake up replacement
+ if (tryRelease(c, ws[sp & m], AC_UNIT))
+ break;
+ }
+ else if (ex != null && (c & ADD_WORKER) != 0L) {
+ tryAddWorker(c); // create replacement
+ break;
+ }
+ else // don't need replacement
+ break;
+ }
+ if (ex == null) // help clean on way out
ForkJoinTask.helpExpungeStaleExceptions();
- else // rethrow
+ else // rethrow
ForkJoinTask.rethrow(ex);
}
- // Submissions
-
- /**
- * Unless shutting down, adds the given task to a submission queue
- * at submitter's current queue index (modulo submission
- * range). Only the most common path is directly handled in this
- * method. All others are relayed to fullExternalPush.
- *
- * @param task the task. Caller must ensure non-null.
- */
- final void externalPush(ForkJoinTask<?> task) {
- WorkQueue q; int m, s, n, am; ForkJoinTask<?>[] a;
- int r = ThreadLocalRandom.getProbe();
- int ps = plock;
- WorkQueue[] ws = workQueues;
- if (ps > 0 && ws != null && (m = (ws.length - 1)) >= 0 &&
- (q = ws[m & r & SQMASK]) != null && r != 0 &&
- U.compareAndSwapInt(q, QLOCK, 0, 1)) { // lock
- if ((a = q.array) != null &&
- (am = a.length - 1) > (n = (s = q.top) - q.base)) {
- int j = ((am & s) << ASHIFT) + ABASE;
- U.putOrderedObject(a, j, task);
- q.top = s + 1; // push on to deque
- q.qlock = 0;
- if (n <= 1)
- signalWork(ws, q);
- return;
- }
- q.qlock = 0;
- }
- fullExternalPush(task);
- }
-
- /**
- * Full version of externalPush. This method is called, among
- * other times, upon the first submission of the first task to the
- * pool, so must perform secondary initialization. It also
- * detects first submission by an external thread by looking up
- * its ThreadLocal, and creates a new shared queue if the one at
- * index if empty or contended. The plock lock body must be
- * exception-free (so no try/finally) so we optimistically
- * allocate new queues outside the lock and throw them away if
- * (very rarely) not needed.
- *
- * Secondary initialization occurs when plock is zero, to create
- * workQueue array and set plock to a valid value. This lock body
- * must also be exception-free. Because the plock seq value can
- * eventually wrap around zero, this method harmlessly fails to
- * reinitialize if workQueues exists, while still advancing plock.
- */
- private void fullExternalPush(ForkJoinTask<?> task) {
- int r;
- if ((r = ThreadLocalRandom.getProbe()) == 0) {
- ThreadLocalRandom.localInit();
- r = ThreadLocalRandom.getProbe();
- }
- for (;;) {
- WorkQueue[] ws; WorkQueue q; int ps, m, k;
- boolean move = false;
- if ((ps = plock) < 0)
- throw new RejectedExecutionException();
- else if (ps == 0 || (ws = workQueues) == null ||
- (m = ws.length - 1) < 0) { // initialize workQueues
- int p = parallelism; // find power of two table size
- int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots
- n |= n >>> 1; n |= n >>> 2; n |= n >>> 4;
- n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1;
- WorkQueue[] nws = ((ws = workQueues) == null || ws.length == 0 ?
- new WorkQueue[n] : null);
- if (((ps = plock) & PL_LOCK) != 0 ||
- !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
- ps = acquirePlock();
- if (((ws = workQueues) == null || ws.length == 0) && nws != null)
- workQueues = nws;
- int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
- if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
- releasePlock(nps);
- }
- else if ((q = ws[k = r & m & SQMASK]) != null) {
- if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) {
- ForkJoinTask<?>[] a = q.array;
- int s = q.top;
- boolean submitted = false;
- try { // locked version of push
- if ((a != null && a.length > s + 1 - q.base) ||
- (a = q.growArray()) != null) { // must presize
- int j = (((a.length - 1) & s) << ASHIFT) + ABASE;
- U.putOrderedObject(a, j, task);
- q.top = s + 1;
- submitted = true;
- }
- } finally {
- q.qlock = 0; // unlock
- }
- if (submitted) {
- signalWork(ws, q);
- return;
- }
- }
- move = true; // move on failure
- }
- else if (((ps = plock) & PL_LOCK) == 0) { // create new queue
- q = new WorkQueue(this, null, SHARED_QUEUE, r);
- q.poolIndex = (short)k;
- if (((ps = plock) & PL_LOCK) != 0 ||
- !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
- ps = acquirePlock();
- if ((ws = workQueues) != null && k < ws.length && ws[k] == null)
- ws[k] = q;
- int nps = (ps & SHUTDOWN) | ((ps + PL_LOCK) & ~SHUTDOWN);
- if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
- releasePlock(nps);
- }
- else
- move = true; // move if busy
- if (move)
- r = ThreadLocalRandom.advanceProbe(r);
- }
- }
-
- // Maintaining ctl counts
-
- /**
- * Increments active count; mainly called upon return from blocking.
- */
- final void incrementActiveCount() {
- long c;
- do {} while (!U.compareAndSwapLong
- (this, CTL, c = ctl, ((c & ~AC_MASK) |
- ((c & AC_MASK) + AC_UNIT))));
- }
+ // Signalling
/**
* Tries to create or activate a worker if too few are active.
*
* @param ws the worker array to use to find signallees
- * @param q if non-null, the queue holding tasks to be processed
+ * @param q a WorkQueue --if non-null, don't retry if now empty
*/
final void signalWork(WorkQueue[] ws, WorkQueue q) {
- for (;;) {
- long c; int e, u, i; WorkQueue w; Thread p;
- if ((u = (int)((c = ctl) >>> 32)) >= 0)
- break;
- if ((e = (int)c) <= 0) {
- if ((short)u < 0)
- tryAddWorker();
+ long c; int sp, i; WorkQueue v; Thread p;
+ while ((c = ctl) < 0L) { // too few active
+ if ((sp = (int)c) == 0) { // no idle workers
+ if ((c & ADD_WORKER) != 0L) // too few workers
+ tryAddWorker(c);
break;
}
- if (ws == null || ws.length <= (i = e & SMASK) ||
- (w = ws[i]) == null)
+ if (ws == null) // unstarted/terminated
break;
- long nc = (((long)(w.nextWait & E_MASK)) |
- ((long)(u + UAC_UNIT)) << 32);
- int ne = (e + E_SEQ) & E_MASK;
- if (w.eventCount == (e | INT_SIGN) &&
- U.compareAndSwapLong(this, CTL, c, nc)) {
- w.eventCount = ne;
- if ((p = w.parker) != null)
+ if (ws.length <= (i = sp & SMASK)) // terminated
+ break;
+ if ((v = ws[i]) == null) // terminating
+ break;
+ int vs = (sp + SS_SEQ) & ~INACTIVE; // next scanState
+ int d = sp - v.scanState; // screen CAS
+ long nc = (UC_MASK & (c + AC_UNIT)) | (SP_MASK & v.stackPred);
+ if (d == 0 && U.compareAndSwapLong(this, CTL, c, nc)) {
+ v.scanState = vs; // activate v
+ if ((p = v.parker) != null)
U.unpark(p);
break;
}
- if (q != null && q.base >= q.top)
+ if (q != null && q.base == q.top) // no more work
break;
}
}
+ /**
+ * Signals and releases worker v if it is top of idle worker
+ * stack. This performs a one-shot version of signalWork only if
+ * there is (apparently) at least one idle worker.
+ *
+ * @param c incoming ctl value
+ * @param v if non-null, a worker
+ * @param inc the increment to active count (zero when compensating)
+ * @return true if successful
+ */
+ private boolean tryRelease(long c, WorkQueue v, long inc) {
+ int sp = (int)c, vs = (sp + SS_SEQ) & ~INACTIVE; Thread p;
+ if (v != null && v.scanState == sp) { // v is at top of stack
+ long nc = (UC_MASK & (c + inc)) | (SP_MASK & v.stackPred);
+ if (U.compareAndSwapLong(this, CTL, c, nc)) {
+ v.scanState = vs;
+ if ((p = v.parker) != null)
+ U.unpark(p);
+ return true;
+ }
+ }
+ return false;
+ }
+
// Scanning for tasks
/**
* Top-level runloop for workers, called by ForkJoinWorkerThread.run.
*/
final void runWorker(WorkQueue w) {
- w.growArray(); // allocate queue
- for (int r = w.hint; scan(w, r) == 0; ) {
+ w.growArray(); // allocate queue
+ int seed = w.hint; // initially holds randomization hint
+ int r = (seed == 0) ? 1 : seed; // avoid 0 for xorShift
+ for (ForkJoinTask<?> t;;) {
+ if ((t = scan(w, r)) != null)
+ w.runTask(t);
+ else if (!awaitWork(w, r))
+ break;
r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
}
}
/**
- * Scans for and, if found, runs one task, else possibly
- * inactivates the worker. This method operates on single reads of
- * volatile state and is designed to be re-invoked continuously,
- * in part because it returns upon detecting inconsistencies,
- * contention, or state changes that indicate possible success on
- * re-invocation.
- *
- * The scan searches for tasks across queues starting at a random
- * index, checking each at least twice. The scan terminates upon
- * either finding a non-empty queue, or completing the sweep. If
- * the worker is not inactivated, it takes and runs a task from
- * this queue. Otherwise, if not activated, it tries to activate
- * itself or some other worker by signalling. On failure to find a
- * task, returns (for retry) if pool state may have changed during
- * an empty scan, or tries to inactivate if active, else possibly
- * blocks or terminates via method awaitWork.
+ * Scans for and tries to steal a top-level task. Scans start at a
+ * random location, randomly moving on apparent contention,
+ * otherwise continuing linearly until reaching two consecutive
+ * empty passes over all queues with the same checksum (summing
+ * each base index of each queue, that moves on each steal), at
+ * which point the worker tries to inactivate and then re-scans,
+ * attempting to re-activate (itself or some other worker) if
+ * finding a task; otherwise returning null to await work. Scans
+ * otherwise touch as little memory as possible, to reduce
+ * disruption on other scanning threads.
*
* @param w the worker (via its WorkQueue)
* @param r a random seed
- * @return worker qlock status if would have waited, else 0
+ * @return a task, or null if none found
*/
- private final int scan(WorkQueue w, int r) {
+ private ForkJoinTask<?> scan(WorkQueue w, int r) {
WorkQueue[] ws; int m;
- long c = ctl; // for consistency check
- if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && w != null) {
- for (int j = m + m + 1, ec = w.eventCount;;) {
- WorkQueue q; int b, e; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
- if ((q = ws[(r - j) & m]) != null &&
- (b = q.base) - q.top < 0 && (a = q.array) != null) {
- long i = (((a.length - 1) & b) << ASHIFT) + ABASE;
- if ((t = ((ForkJoinTask<?>)
- U.getObjectVolatile(a, i))) != null) {
- if (ec < 0)
- helpRelease(c, ws, w, q, b);
- else if (q.base == b &&
- U.compareAndSwapObject(a, i, t, null)) {
- U.putOrderedInt(q, QBASE, b + 1);
- if ((b + 1) - q.top < 0)
- signalWork(ws, q);
- w.runTask(t);
+ if ((ws = workQueues) != null && (m = ws.length - 1) > 0 && w != null) {
+ int ss = w.scanState; // initially non-negative
+ for (int origin = r & m, k = origin, oldSum = 0, checkSum = 0;;) {
+ WorkQueue q; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
+ int b, n; long c;
+ if ((q = ws[k]) != null) {
+ if ((n = (b = q.base) - q.top) < 0 &&
+ (a = q.array) != null) { // non-empty
+ long i = (((a.length - 1) & b) << ASHIFT) + ABASE;
+ if ((t = ((ForkJoinTask<?>)
+ U.getObjectVolatile(a, i))) != null &&
+ q.base == b) {
+ if (ss >= 0) {
+ if (U.compareAndSwapObject(a, i, t, null)) {
+ q.base = b + 1;
+ if (n < -1) // signal others
+ signalWork(ws, q);
+ return t;
+ }
+ }
+ else if (oldSum == 0 && // try to activate
+ w.scanState < 0)
+ tryRelease(c = ctl, ws[m & (int)c], AC_UNIT);
}
+ if (ss < 0) // refresh
+ ss = w.scanState;
+ r ^= r << 1; r ^= r >>> 3; r ^= r << 10;
+ origin = k = r & m; // move and rescan
+ oldSum = checkSum = 0;
+ continue;
}
- break;
+ checkSum += b;
}
- else if (--j < 0) {
- if ((ec | (e = (int)c)) < 0) // inactive or terminating
- return awaitWork(w, c, ec);
- else if (ctl == c) { // try to inactivate and enqueue
- long nc = (long)ec | ((c - AC_UNIT) & (AC_MASK|TC_MASK));
- w.nextWait = e;
- w.eventCount = ec | INT_SIGN;
- if (!U.compareAndSwapLong(this, CTL, c, nc))
- w.eventCount = ec; // back out
+ if ((k = (k + 1) & m) == origin) { // continue until stable
+ if ((ss >= 0 || (ss == (ss = w.scanState))) &&
+ oldSum == (oldSum = checkSum)) {
+ if (ss < 0 || w.qlock < 0) // already inactive
+ break;
+ int ns = ss | INACTIVE; // try to inactivate
+ long nc = ((SP_MASK & ns) |
+ (UC_MASK & ((c = ctl) - AC_UNIT)));
+ w.stackPred = (int)c; // hold prev stack top
+ U.putInt(w, QSCANSTATE, ns);
+ if (U.compareAndSwapLong(this, CTL, c, nc))
+ ss = ns;
+ else
+ w.scanState = ss; // back out
}
- break;
+ checkSum = 0;
}
}
}
- return 0;
+ return null;
}
/**
- * A continuation of scan(), possibly blocking or terminating
- * worker w. Returns without blocking if pool state has apparently
- * changed since last invocation. Also, if inactivating w has
- * caused the pool to become quiescent, checks for pool
+ * Possibly blocks worker w waiting for a task to steal, or
+ * returns false if the worker should terminate. If inactivating
+ * w has caused the pool to become quiescent, checks for pool
* termination, and, so long as this is not the only worker, waits
- * for event for up to a given duration. On timeout, if ctl has
- * not changed, terminates the worker, which will in turn wake up
+ * for up to a given duration. On timeout, if ctl has not
+ * changed, terminates the worker, which will in turn wake up
* another worker to possibly repeat this process.
*
* @param w the calling worker
- * @param c the ctl value on entry to scan
- * @param ec the worker's eventCount on entry to scan
+ * @param r a random seed (for spins)
+ * @return false if the worker should terminate
*/
- private final int awaitWork(WorkQueue w, long c, int ec) {
- int stat, ns; long parkTime, deadline;
- if ((stat = w.qlock) >= 0 && w.eventCount == ec && ctl == c &&
- !Thread.interrupted()) {
- int e = (int)c;
- int u = (int)(c >>> 32);
- int d = (u >> UAC_SHIFT) + parallelism; // active count
-
- if (e < 0 || (d <= 0 && tryTerminate(false, false)))
- stat = w.qlock = -1; // pool is terminating
- else if ((ns = w.nsteals) != 0) { // collect steals and retry
- w.nsteals = 0;
- U.getAndAddLong(this, STEALCOUNT, (long)ns);
+ private boolean awaitWork(WorkQueue w, int r) {
+ if (w == null || w.qlock < 0) // w is terminating
+ return false;
+ for (int pred = w.stackPred, spins = SPINS, ss;;) {
+ if ((ss = w.scanState) >= 0)
+ break;
+ else if (spins > 0) {
+ r ^= r << 6; r ^= r >>> 21; r ^= r << 7;
+ if (r >= 0 && --spins == 0) { // randomize spins
+ WorkQueue v; WorkQueue[] ws; int s, j; AtomicLong sc;
+ if (pred != 0 && (ws = workQueues) != null &&
+ (j = pred & SMASK) < ws.length &&
+ (v = ws[j]) != null && // see if pred parking
+ (v.parker == null || v.scanState >= 0))
+ spins = SPINS; // continue spinning
+ }
}
- else {
- long pc = ((d > 0 || ec != (e | INT_SIGN)) ? 0L :
- ((long)(w.nextWait & E_MASK)) | // ctl to restore
- ((long)(u + UAC_UNIT)) << 32);
- if (pc != 0L) { // timed wait if last waiter
- int dc = -(short)(c >>> TC_SHIFT);
- parkTime = (dc < 0 ? FAST_IDLE_TIMEOUT:
- (dc + 1) * IDLE_TIMEOUT);
+ else if (w.qlock < 0) // recheck after spins
+ return false;
+ else if (!Thread.interrupted()) {
+ long c, prevctl, parkTime, deadline;
+ int ac = (int)((c = ctl) >> AC_SHIFT) + (config & SMASK);
+ if ((ac <= 0 && tryTerminate(false, false)) ||
+ (runState & STOP) != 0) // pool terminating
+ return false;
+ if (ac <= 0 && ss == (int)c) { // is last waiter
+ prevctl = (UC_MASK & (c + AC_UNIT)) | (SP_MASK & pred);
+ int t = (short)(c >>> TC_SHIFT); // shrink excess spares
+ if (t > 2 && U.compareAndSwapLong(this, CTL, c, prevctl))
+ return false; // else use timed wait
+ parkTime = IDLE_TIMEOUT * ((t >= 0) ? 1 : 1 - t);
deadline = System.nanoTime() + parkTime - TIMEOUT_SLOP;
}
else
- parkTime = deadline = 0L;
- if (w.eventCount == ec && ctl == c) {
- Thread wt = Thread.currentThread();
- U.putObject(wt, PARKBLOCKER, this);
- w.parker = wt; // emulate LockSupport.park
- if (w.eventCount == ec && ctl == c)
- U.park(false, parkTime); // must recheck before park
- w.parker = null;
- U.putObject(wt, PARKBLOCKER, null);
- if (parkTime != 0L && ctl == c &&
- deadline - System.nanoTime() <= 0L &&
- U.compareAndSwapLong(this, CTL, c, pc))
- stat = w.qlock = -1; // shrink pool
+ prevctl = parkTime = deadline = 0L;
+ Thread wt = Thread.currentThread();
+ U.putObject(wt, PARKBLOCKER, this); // emulate LockSupport
+ w.parker = wt;
+ if (w.scanState < 0 && ctl == c) // recheck before park
+ U.park(false, parkTime);
+ U.putOrderedObject(w, QPARKER, null);
+ U.putObject(wt, PARKBLOCKER, null);
+ if (w.scanState >= 0)
+ break;
+ if (parkTime != 0L && ctl == c &&
+ deadline - System.nanoTime() <= 0L &&
+ U.compareAndSwapLong(this, CTL, c, prevctl))
+ return false; // shrink pool
+ }
+ }
+ return true;
+ }
+
+ // Joining tasks
+
+ /**
+ * Tries to steal and run tasks within the target's computation.
+ * Uses a variant of the top-level algorithm, restricted to tasks
+ * with the given task as ancestor: It prefers taking and running
+ * eligible tasks popped from the worker's own queue (via
+ * popCC). Otherwise it scans others, randomly moving on
+ * contention or execution, deciding to give up based on a
+ * checksum (via return codes frob pollAndExecCC). The maxTasks
+ * argument supports external usages; internal calls use zero,
+ * allowing unbounded steps (external calls trap non-positive
+ * values).
+ *
+ * @param w caller
+ * @param maxTasks if non-zero, the maximum number of other tasks to run
+ * @return task status on exit
+ */
+ final int helpComplete(WorkQueue w, CountedCompleter<?> task,
+ int maxTasks) {
+ WorkQueue[] ws; int s = 0, m;
+ if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 &&
+ task != null && w != null) {
+ int mode = w.config; // for popCC
+ int r = w.hint ^ w.top; // arbitrary seed for origin
+ int origin = r & m; // first queue to scan
+ int h = 1; // 1:ran, >1:contended, <0:hash
+ for (int k = origin, oldSum = 0, checkSum = 0;;) {
+ CountedCompleter<?> p; WorkQueue q;
+ if ((s = task.status) < 0)
+ break;
+ if (h == 1 && (p = w.popCC(task, mode)) != null) {
+ p.doExec(); // run local task
+ if (maxTasks != 0 && --maxTasks == 0)
+ break;
+ origin = k; // reset
+ oldSum = checkSum = 0;
+ }
+ else { // poll other queues
+ if ((q = ws[k]) == null)
+ h = 0;
+ else if ((h = q.pollAndExecCC(task)) < 0)
+ checkSum += h;
+ if (h > 0) {
+ if (h == 1 && maxTasks != 0 && --maxTasks == 0)
+ break;
+ r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
+ origin = k = r & m; // move and restart
+ oldSum = checkSum = 0;
+ }
+ else if ((k = (k + 1) & m) == origin) {
+ if (oldSum == (oldSum = checkSum))
+ break;
+ checkSum = 0;
+ }
}
}
}
- return stat;
- }
-
- /**
- * Possibly releases (signals) a worker. Called only from scan()
- * when a worker with apparently inactive status finds a non-empty
- * queue. This requires revalidating all of the associated state
- * from caller.
- */
- private final void helpRelease(long c, WorkQueue[] ws, WorkQueue w,
- WorkQueue q, int b) {
- WorkQueue v; int e, i; Thread p;
- if (w != null && w.eventCount < 0 && (e = (int)c) > 0 &&
- ws != null && ws.length > (i = e & SMASK) &&
- (v = ws[i]) != null && ctl == c) {
- long nc = (((long)(v.nextWait & E_MASK)) |
- ((long)((int)(c >>> 32) + UAC_UNIT)) << 32);
- int ne = (e + E_SEQ) & E_MASK;
- if (q != null && q.base == b && w.eventCount < 0 &&
- v.eventCount == (e | INT_SIGN) &&
- U.compareAndSwapLong(this, CTL, c, nc)) {
- v.eventCount = ne;
- if ((p = v.parker) != null)
- U.unpark(p);
- }
- }
+ return s;
}
/**
@@ -1799,268 +1901,167 @@
* execute tasks from. The first call to this method upon a
* waiting join will often entail scanning/search, (which is OK
* because the joiner has nothing better to do), but this method
- * leaves hints in workers to speed up subsequent calls. The
- * implementation is very branchy to cope with potential
- * inconsistencies or loops encountering chains that are stale,
- * unknown, or so long that they are likely cyclic.
+ * leaves hints in workers to speed up subsequent calls.
*
- * @param joiner the joining worker
+ * @param w caller
* @param task the task to join
- * @return 0 if no progress can be made, negative if task
- * known complete, else positive
*/
- private int tryHelpStealer(WorkQueue joiner, ForkJoinTask<?> task) {
- int stat = 0, steps = 0; // bound to avoid cycles
- if (task != null && joiner != null &&
- joiner.base - joiner.top >= 0) { // hoist checks
- restart: for (;;) {
- ForkJoinTask<?> subtask = task; // current target
- for (WorkQueue j = joiner, v;;) { // v is stealer of subtask
- WorkQueue[] ws; int m, s, h;
- if ((s = task.status) < 0) {
- stat = s;
- break restart;
- }
- if ((ws = workQueues) == null || (m = ws.length - 1) <= 0)
- break restart; // shutting down
- if ((v = ws[h = (j.hint | 1) & m]) == null ||
- v.currentSteal != subtask) {
- for (int origin = h;;) { // find stealer
- if (((h = (h + 2) & m) & 15) == 1 &&
- (subtask.status < 0 || j.currentJoin != subtask))
- continue restart; // occasional staleness check
- if ((v = ws[h]) != null &&
- v.currentSteal == subtask) {
- j.hint = h; // save hint
+ private void helpStealer(WorkQueue w, ForkJoinTask<?> task) {
+ WorkQueue[] ws = workQueues;
+ int oldSum = 0, checkSum, m;
+ if (ws != null && (m = ws.length - 1) >= 0 && w != null &&
+ task != null) {
+ do { // restart point
+ checkSum = 0; // for stability check
+ ForkJoinTask<?> subtask;
+ WorkQueue j = w, v; // v is subtask stealer
+ descent: for (subtask = task; subtask.status >= 0; ) {
+ for (int h = j.hint | 1, k = 0, i; ; k += 2) {
+ if (k > m) // can't find stealer
+ break descent;
+ if ((v = ws[i = (h + k) & m]) != null) {
+ if (v.currentSteal == subtask) {
+ j.hint = i;
break;
}
- if (h == origin)
- break restart; // cannot find stealer
+ checkSum += v.base;
}
}
- for (;;) { // help stealer or descend to its stealer
+ for (;;) { // help v or descend
ForkJoinTask<?>[] a; int b;
- if (subtask.status < 0) // surround probes with
- continue restart; // consistency checks
- if ((b = v.base) - v.top < 0 && (a = v.array) != null) {
- int i = (((a.length - 1) & b) << ASHIFT) + ABASE;
- ForkJoinTask<?> t =
- (ForkJoinTask<?>)U.getObjectVolatile(a, i);
- if (subtask.status < 0 || j.currentJoin != subtask ||
- v.currentSteal != subtask)
- continue restart; // stale
- stat = 1; // apparent progress
- if (v.base == b) {
- if (t == null)
- break restart;
- if (U.compareAndSwapObject(a, i, t, null)) {
- U.putOrderedInt(v, QBASE, b + 1);
- ForkJoinTask<?> ps = joiner.currentSteal;
- int jt = joiner.top;
- do {
- joiner.currentSteal = t;
- t.doExec(); // clear local tasks too
- } while (task.status >= 0 &&
- joiner.top != jt &&
- (t = joiner.pop()) != null);
- joiner.currentSteal = ps;
- break restart;
- }
- }
+ checkSum += (b = v.base);
+ ForkJoinTask<?> next = v.currentJoin;
+ if (subtask.status < 0 || j.currentJoin != subtask ||
+ v.currentSteal != subtask) // stale
+ break descent;
+ if (b - v.top >= 0 || (a = v.array) == null) {
+ if ((subtask = next) == null)
+ break descent;
+ j = v;
+ break;
}
- else { // empty -- try to descend
- ForkJoinTask<?> next = v.currentJoin;
- if (subtask.status < 0 || j.currentJoin != subtask ||
- v.currentSteal != subtask)
- continue restart; // stale
- else if (next == null || ++steps == MAX_HELP)
- break restart; // dead-end or maybe cyclic
- else {
- subtask = next;
- j = v;
- break;
+ int i = (((a.length - 1) & b) << ASHIFT) + ABASE;
+ ForkJoinTask<?> t = ((ForkJoinTask<?>)
+ U.getObjectVolatile(a, i));
+ if (v.base == b) {
+ if (t == null) // stale
+ break descent;
+ if (U.compareAndSwapObject(a, i, t, null)) {
+ v.base = b + 1;
+ ForkJoinTask<?> ps = w.currentSteal;
+ int top = w.top;
+ do {
+ U.putOrderedObject(w, QCURRENTSTEAL, t);
+ t.doExec(); // clear local tasks too
+ } while (task.status >= 0 &&
+ w.top != top &&
+ (t = w.pop()) != null);
+ U.putOrderedObject(w, QCURRENTSTEAL, ps);
+ if (w.base != w.top)
+ return; // can't further help
}
}
}
}
- }
+ } while (task.status >= 0 && oldSum != (oldSum = checkSum));
}
- return stat;
- }
-
- /**
- * Analog of tryHelpStealer for CountedCompleters. Tries to steal
- * and run tasks within the target's computation.
- *
- * @param task the task to join
- * @param maxTasks the maximum number of other tasks to run
- */
- final int helpComplete(WorkQueue joiner, CountedCompleter<?> task,
- int maxTasks) {
- WorkQueue[] ws; int m;
- int s = 0;
- if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 &&
- joiner != null && task != null) {
- int j = joiner.poolIndex;
- int scans = m + m + 1;
- long c = 0L; // for stability check
- for (int k = scans; ; j += 2) {
- WorkQueue q;
- if ((s = task.status) < 0)
- break;
- else if (joiner.internalPopAndExecCC(task)) {
- if (--maxTasks <= 0) {
- s = task.status;
- break;
- }
- k = scans;
- }
- else if ((s = task.status) < 0)
- break;
- else if ((q = ws[j & m]) != null && q.pollAndExecCC(task)) {
- if (--maxTasks <= 0) {
- s = task.status;
- break;
- }
- k = scans;
- }
- else if (--k < 0) {
- if (c == (c = ctl))
- break;
- k = scans;
- }
- }
- }
- return s;
}
/**
* Tries to decrement active count (sometimes implicitly) and
* possibly release or create a compensating worker in preparation
- * for blocking. Fails on contention or termination. Otherwise,
- * adds a new thread if no idle workers are available and pool
- * may become starved.
+ * for blocking. Returns false (retryable by caller), on
+ * contention, detected staleness, instability, or termination.
*
- * @param c the assumed ctl value
+ * @param w caller
*/
- final boolean tryCompensate(long c) {
- WorkQueue[] ws = workQueues;
- int pc = parallelism, e = (int)c, m, tc;
- if (ws != null && (m = ws.length - 1) >= 0 && e >= 0 && ctl == c) {
- WorkQueue w = ws[e & m];
- if (e != 0 && w != null) {
- Thread p;
- long nc = ((long)(w.nextWait & E_MASK) |
- (c & (AC_MASK|TC_MASK)));
- int ne = (e + E_SEQ) & E_MASK;
- if (w.eventCount == (e | INT_SIGN) &&
- U.compareAndSwapLong(this, CTL, c, nc)) {
- w.eventCount = ne;
- if ((p = w.parker) != null)
- U.unpark(p);
- return true; // replace with idle worker
+ private boolean tryCompensate(WorkQueue w) {
+ boolean canBlock;
+ WorkQueue[] ws; long c; int m, pc, sp;
+ if (w == null || w.qlock < 0 || // caller terminating
+ (ws = workQueues) == null || (m = ws.length - 1) <= 0 ||
+ (pc = config & SMASK) == 0) // parallelism disabled
+ canBlock = false;
+ else if ((sp = (int)(c = ctl)) != 0) // release idle worker
+ canBlock = tryRelease(c, ws[sp & m], 0L);
+ else {
+ int ac = (int)(c >> AC_SHIFT) + pc;
+ int tc = (short)(c >> TC_SHIFT) + pc;
+ int nbusy = 0; // validate saturation
+ for (int i = 0; i <= m; ++i) { // two passes of odd indices
+ WorkQueue v;
+ if ((v = ws[((i << 1) | 1) & m]) != null) {
+ if ((v.scanState & SCANNING) != 0)
+ break;
+ ++nbusy;
}
}
- else if ((tc = (short)(c >>> TC_SHIFT)) >= 0 &&
- (int)(c >> AC_SHIFT) + pc > 1) {
- long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK);
- if (U.compareAndSwapLong(this, CTL, c, nc))
- return true; // no compensation
+ if (nbusy != (tc << 1) || ctl != c)
+ canBlock = false; // unstable or stale
+ else if (tc >= pc && ac > 1 && w.isEmpty()) {
+ long nc = ((AC_MASK & (c - AC_UNIT)) |
+ (~AC_MASK & c)); // uncompensated
+ canBlock = U.compareAndSwapLong(this, CTL, c, nc);
}
- else if (tc + pc < MAX_CAP) {
- long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK);
- if (U.compareAndSwapLong(this, CTL, c, nc)) {
- ForkJoinWorkerThreadFactory fac;
- Throwable ex = null;
- ForkJoinWorkerThread wt = null;
- try {
- if ((fac = factory) != null &&
- (wt = fac.newThread(this)) != null) {
- wt.start();
- return true;
- }
- } catch (Throwable rex) {
- ex = rex;
- }
- deregisterWorker(wt, ex); // clean up and return false
- }
+ else if (tc >= MAX_CAP ||
+ (this == common && tc >= pc + commonMaxSpares))
+ throw new RejectedExecutionException(
+ "Thread limit exceeded replacing blocked worker");
+ else { // similar to tryAddWorker
+ boolean add = false; int rs; // CAS within lock
+ long nc = ((AC_MASK & c) |
+ (TC_MASK & (c + TC_UNIT)));
+ if (((rs = lockRunState()) & STOP) == 0)
+ add = U.compareAndSwapLong(this, CTL, c, nc);
+ unlockRunState(rs, rs & ~RSLOCK);
+ canBlock = add && createWorker(); // throws on exception
}
}
- return false;
+ return canBlock;
}
/**
- * Helps and/or blocks until the given task is done.
+ * Helps and/or blocks until the given task is done or timeout.
*
- * @param joiner the joining worker
+ * @param w caller
* @param task the task
+ * @param deadline for timed waits, if nonzero
* @return task status on exit
*/
- final int awaitJoin(WorkQueue joiner, ForkJoinTask<?> task) {
+ final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
int s = 0;
- if (task != null && (s = task.status) >= 0 && joiner != null) {
- ForkJoinTask<?> prevJoin = joiner.currentJoin;
- joiner.currentJoin = task;
- do {} while (joiner.tryRemoveAndExec(task) && // process local tasks
- (s = task.status) >= 0);
- if (s >= 0 && (task instanceof CountedCompleter))
- s = helpComplete(joiner, (CountedCompleter<?>)task, Integer.MAX_VALUE);
- long cc = 0; // for stability checks
- while (s >= 0 && (s = task.status) >= 0) {
- if ((s = tryHelpStealer(joiner, task)) == 0 &&
- (s = task.status) >= 0) {
- if (!tryCompensate(cc))
- cc = ctl;
- else {
- if (task.trySetSignal() && (s = task.status) >= 0) {
- synchronized (task) {
- if (task.status >= 0) {
- try { // see ForkJoinTask
- task.wait(); // for explanation
- } catch (InterruptedException ie) {
- }
- }
- else
- task.notifyAll();
- }
- }
- long c; // reactivate
- do {} while (!U.compareAndSwapLong
- (this, CTL, c = ctl,
- ((c & ~AC_MASK) |
- ((c & AC_MASK) + AC_UNIT))));
- }
+ if (task != null && w != null) {
+ ForkJoinTask<?> prevJoin = w.currentJoin;
+ U.putOrderedObject(w, QCURRENTJOIN, task);
+ CountedCompleter<?> cc = (task instanceof CountedCompleter) ?
+ (CountedCompleter<?>)task : null;
+ for (;;) {
+ if ((s = task.status) < 0)
+ break;
+ if (cc != null)
+ helpComplete(w, cc, 0);
+ else if (w.base == w.top || w.tryRemoveAndExec(task))
+ helpStealer(w, task);
+ if ((s = task.status) < 0)
+ break;
+ long ms, ns;
+ if (deadline == 0L)
+ ms = 0L;
+ else if ((ns = deadline - System.nanoTime()) <= 0L)
+ break;
+ else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
+ ms = 1L;
+ if (tryCompensate(w)) {
+ task.internalWait(ms);
+ U.getAndAddLong(this, CTL, AC_UNIT);
}
}
- joiner.currentJoin = prevJoin;
+ U.putOrderedObject(w, QCURRENTJOIN, prevJoin);
}
return s;
}
- /**
- * Stripped-down variant of awaitJoin used by timed joins. Tries
- * to help join only while there is continuous progress. (Caller
- * will then enter a timed wait.)
- *
- * @param joiner the joining worker
- * @param task the task
- */
- final void helpJoinOnce(WorkQueue joiner, ForkJoinTask<?> task) {
- int s;
- if (joiner != null && task != null && (s = task.status) >= 0) {
- ForkJoinTask<?> prevJoin = joiner.currentJoin;
- joiner.currentJoin = task;
- do {} while (joiner.tryRemoveAndExec(task) && // process local tasks
- (s = task.status) >= 0);
- if (s >= 0) {
- if (task instanceof CountedCompleter)
- helpComplete(joiner, (CountedCompleter<?>)task, Integer.MAX_VALUE);
- do {} while (task.status >= 0 &&
- tryHelpStealer(joiner, task) > 0);
- }
- joiner.currentJoin = prevJoin;
- }
- }
+ // Specialized scanning
/**
* Returns a (probably) non-empty steal queue, if one is found
@@ -2068,19 +2069,24 @@
* caller if, by the time it tries to use the queue, it is empty.
*/
private WorkQueue findNonEmptyStealQueue() {
+ WorkQueue[] ws; int m; // one-shot version of scan loop
int r = ThreadLocalRandom.nextSecondarySeed();
- for (;;) {
- int ps = plock, m; WorkQueue[] ws; WorkQueue q;
- if ((ws = workQueues) != null && (m = ws.length - 1) >= 0) {
- for (int j = (m + 1) << 2; j >= 0; --j) {
- if ((q = ws[(((r - j) << 1) | 1) & m]) != null &&
- q.base - q.top < 0)
+ if ((ws = workQueues) != null && (m = ws.length - 1) >= 0) {
+ for (int origin = r & m, k = origin, oldSum = 0, checkSum = 0;;) {
+ WorkQueue q; int b;
+ if ((q = ws[k]) != null) {
+ if ((b = q.base) - q.top < 0)
return q;
+ checkSum += b;
+ }
+ if ((k = (k + 1) & m) == origin) {
+ if (oldSum == (oldSum = checkSum))
+ break;
+ checkSum = 0;
}
}
- if (plock == ps)
- return null;
}
+ return null;
}
/**
@@ -2090,35 +2096,34 @@
* find tasks either.
*/
final void helpQuiescePool(WorkQueue w) {
- ForkJoinTask<?> ps = w.currentSteal;
+ ForkJoinTask<?> ps = w.currentSteal; // save context
for (boolean active = true;;) {
long c; WorkQueue q; ForkJoinTask<?> t; int b;
- while ((t = w.nextLocalTask()) != null)
- t.doExec();
+ w.execLocalTasks(); // run locals before each scan
if ((q = findNonEmptyStealQueue()) != null) {
if (!active) { // re-establish active count
active = true;
- do {} while (!U.compareAndSwapLong
- (this, CTL, c = ctl,
- ((c & ~AC_MASK) |
- ((c & AC_MASK) + AC_UNIT))));
+ U.getAndAddLong(this, CTL, AC_UNIT);
}
- if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null)
- w.runTask(t);
+ if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null) {
+ U.putOrderedObject(w, QCURRENTSTEAL, t);
+ t.doExec();
+ if (++w.nsteals < 0)
+ w.transferStealCount(this);
+ }
}
else if (active) { // decrement active count without queuing
- long nc = ((c = ctl) & ~AC_MASK) | ((c & AC_MASK) - AC_UNIT);
- if ((int)(nc >> AC_SHIFT) + parallelism == 0)
+ long nc = (AC_MASK & ((c = ctl) - AC_UNIT)) | (~AC_MASK & c);
+ if ((int)(nc >> AC_SHIFT) + (config & SMASK) <= 0)
break; // bypass decrement-then-increment
if (U.compareAndSwapLong(this, CTL, c, nc))
active = false;
}
- else if ((int)((c = ctl) >> AC_SHIFT) + parallelism <= 0 &&
- U.compareAndSwapLong
- (this, CTL, c, ((c & ~AC_MASK) |
- ((c & AC_MASK) + AC_UNIT))))
+ else if ((int)((c = ctl) >> AC_SHIFT) + (config & SMASK) <= 0 &&
+ U.compareAndSwapLong(this, CTL, c, c + AC_UNIT))
break;
}
+ U.putOrderedObject(w, QCURRENTSTEAL, ps);
}
/**
@@ -2141,7 +2146,7 @@
/**
* Returns a cheap heuristic guide for task partitioning when
* programmers, frameworks, tools, or languages have little or no
- * idea about task granularity. In essence by offering this
+ * idea about task granularity. In essence, by offering this
* method, we ask users only about tradeoffs in overhead vs
* expected throughput and its variance, rather than how finely to
* partition tasks.
@@ -2179,15 +2184,12 @@
* many of these by further considering the number of "idle"
* threads, that are known to have zero queued tasks, so
* compensate by a factor of (#idle/#active) threads.
- *
- * Note: The approximation of #busy workers as #active workers is
- * not very good under current signalling scheme, and should be
- * improved.
*/
static int getSurplusQueuedTaskCount() {
Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q;
if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)) {
- int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).parallelism;
+ int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).
+ config & SMASK;
int n = (q = wt.workQueue).top - q.base;
int a = (int)(pool.ctl >> AC_SHIFT) + p;
return n - (a > (p >>>= 1) ? 0 :
@@ -2202,13 +2204,7 @@
// Termination
/**
- * Possibly initiates and/or completes termination. The caller
- * triggering termination runs three passes through workQueues:
- * (0) Setting termination status, followed by wakeups of queued
- * workers; (1) cancelling all tasks; (2) interrupting lagging
- * threads (likely in external tasks, but possibly also blocked in
- * joins). Each pass repeats previous steps because of potential
- * lagging thread creation.
+ * Possibly initiates and/or completes termination.
*
* @param now if true, unconditionally terminate, else only
* if no work and no active workers
@@ -2216,166 +2212,256 @@
* @return true if now terminating or terminated
*/
private boolean tryTerminate(boolean now, boolean enable) {
- int ps;
- if (this == common) // cannot shut down
+ int rs;
+ if (this == common) // cannot shut down
return false;
- if ((ps = plock) >= 0) { // enable by setting plock
+ if ((rs = runState) >= 0) {
if (!enable)
return false;
- if ((ps & PL_LOCK) != 0 ||
- !U.compareAndSwapInt(this, PLOCK, ps, ps += PL_LOCK))
- ps = acquirePlock();
- int nps = ((ps + PL_LOCK) & ~SHUTDOWN) | SHUTDOWN;
- if (!U.compareAndSwapInt(this, PLOCK, ps, nps))
- releasePlock(nps);
+ rs = lockRunState(); // enter SHUTDOWN phase
+ unlockRunState(rs, (rs & ~RSLOCK) | SHUTDOWN);
}
- for (long c;;) {
- if (((c = ctl) & STOP_BIT) != 0) { // already terminating
- if ((short)(c >>> TC_SHIFT) + parallelism <= 0) {
- synchronized (this) {
- notifyAll(); // signal when 0 workers
- }
- }
- return true;
- }
- if (!now) { // check if idle & no tasks
- WorkQueue[] ws; WorkQueue w;
- if ((int)(c >> AC_SHIFT) + parallelism > 0)
- return false;
- if ((ws = workQueues) != null) {
- for (int i = 0; i < ws.length; ++i) {
- if ((w = ws[i]) != null &&
- (!w.isEmpty() ||
- ((i & 1) != 0 && w.eventCount >= 0))) {
- signalWork(ws, w);
- return false;
+
+ if ((rs & STOP) == 0) {
+ if (!now) { // check quiescence
+ for (long oldSum = 0L;;) { // repeat until stable
+ WorkQueue[] ws; WorkQueue w; int m, b; long c;
+ long checkSum = ctl;
+ if ((int)(checkSum >> AC_SHIFT) + (config & SMASK) > 0)
+ return false; // still active workers
+ if ((ws = workQueues) == null || (m = ws.length - 1) <= 0)
+ break; // check queues
+ for (int i = 0; i <= m; ++i) {
+ if ((w = ws[i]) != null) {
+ if ((b = w.base) != w.top || w.scanState >= 0 ||
+ w.currentSteal != null) {
+ tryRelease(c = ctl, ws[m & (int)c], AC_UNIT);
+ return false; // arrange for recheck
+ }
+ checkSum += b;
+ if ((i & 1) == 0)
+ w.qlock = -1; // try to disable external
}
}
+ if (oldSum == (oldSum = checkSum))
+ break;
}
}
- if (U.compareAndSwapLong(this, CTL, c, c | STOP_BIT)) {
- for (int pass = 0; pass < 3; ++pass) {
- WorkQueue[] ws; WorkQueue w; Thread wt;
- if ((ws = workQueues) != null) {
- int n = ws.length;
- for (int i = 0; i < n; ++i) {
- if ((w = ws[i]) != null) {
- w.qlock = -1;
- if (pass > 0) {
- w.cancelAll();
- if (pass > 1 && (wt = w.owner) != null) {
- if (!wt.isInterrupted()) {
- try {
- wt.interrupt();
- } catch (Throwable ignore) {
- }
- }
- U.unpark(wt);
- }
+ if ((runState & STOP) == 0) {
+ rs = lockRunState(); // enter STOP phase
+ unlockRunState(rs, (rs & ~RSLOCK) | STOP);
+ }
+ }
+
+ int pass = 0; // 3 passes to help terminate
+ for (long oldSum = 0L;;) { // or until done or stable
+ WorkQueue[] ws; WorkQueue w; ForkJoinWorkerThread wt; int m;
+ long checkSum = ctl;
+ if ((short)(checkSum >>> TC_SHIFT) + (config & SMASK) <= 0 ||
+ (ws = workQueues) == null || (m = ws.length - 1) <= 0) {
+ if ((runState & TERMINATED) == 0) {
+ rs = lockRunState(); // done
+ unlockRunState(rs, (rs & ~RSLOCK) | TERMINATED);
+ synchronized (this) { notifyAll(); } // for awaitTermination
+ }
+ break;
+ }
+ for (int i = 0; i <= m; ++i) {
+ if ((w = ws[i]) != null) {
+ checkSum += w.base;
+ w.qlock = -1; // try to disable
+ if (pass > 0) {
+ w.cancelAll(); // clear queue
+ if (pass > 1 && (wt = w.owner) != null) {
+ if (!wt.isInterrupted()) {
+ try { // unblock join
+ wt.interrupt();
+ } catch (Throwable ignore) {
}
}
- }
- // Wake up workers parked on event queue
- int i, e; long cc; Thread p;
- while ((e = (int)(cc = ctl) & E_MASK) != 0 &&
- (i = e & SMASK) < n && i >= 0 &&
- (w = ws[i]) != null) {
- long nc = ((long)(w.nextWait & E_MASK) |
- ((cc + AC_UNIT) & AC_MASK) |
- (cc & (TC_MASK|STOP_BIT)));
- if (w.eventCount == (e | INT_SIGN) &&
- U.compareAndSwapLong(this, CTL, cc, nc)) {
- w.eventCount = (e + E_SEQ) & E_MASK;
- w.qlock = -1;
- if ((p = w.parker) != null)
- U.unpark(p);
- }
+ if (w.scanState < 0)
+ U.unpark(wt); // wake up
}
}
}
}
+ if (checkSum != oldSum) { // unstable
+ oldSum = checkSum;
+ pass = 0;
+ }
+ else if (pass > 3 && pass > m) // can't further help
+ break;
+ else if (++pass > 1) { // try to dequeue
+ long c; int j = 0, sp; // bound attempts
+ while (j++ <= m && (sp = (int)(c = ctl)) != 0)
+ tryRelease(c, ws[sp & m], AC_UNIT);
+ }
+ }
+ return true;
+ }
+
+ // External operations
+
+ /**
+ * Full version of externalPush, handling uncommon cases, as well
+ * as performing secondary initialization upon the first
+ * submission of the first task to the pool. It also detects
+ * first submission by an external thread and creates a new shared
+ * queue if the one at index if empty or contended.
+ *
+ * @param task the task. Caller must ensure non-null.
+ */
+ private void externalSubmit(ForkJoinTask<?> task) {
+ int r; // initialize caller's probe
+ if ((r = ThreadLocalRandom.getProbe()) == 0) {
+ ThreadLocalRandom.localInit();
+ r = ThreadLocalRandom.getProbe();
+ }
+ for (;;) {
+ WorkQueue[] ws; WorkQueue q; int rs, m, k;
+ boolean move = false;
+ if ((rs = runState) < 0) {
+ tryTerminate(false, false); // help terminate
+ throw new RejectedExecutionException();
+ }
+ else if ((rs & STARTED) == 0 || // initialize
+ ((ws = workQueues) == null || (m = ws.length - 1) < 0)) {
+ int ns = 0;
+ rs = lockRunState();
+ try {
+ if ((rs & STARTED) == 0) {
+ U.compareAndSwapObject(this, STEALCOUNTER, null,
+ new AtomicLong());
+ // create workQueues array with size a power of two
+ int p = config & SMASK; // ensure at least 2 slots
+ int n = (p > 1) ? p - 1 : 1;
+ n |= n >>> 1; n |= n >>> 2; n |= n >>> 4;
+ n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1;
+ workQueues = new WorkQueue[n];
+ ns = STARTED;
+ }
+ } finally {
+ unlockRunState(rs, (rs & ~RSLOCK) | ns);
+ }
+ }
+ else if ((q = ws[k = r & m & SQMASK]) != null) {
+ if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) {
+ ForkJoinTask<?>[] a = q.array;
+ int s = q.top;
+ boolean submitted = false; // initial submission or resizing
+ try { // locked version of push
+ if ((a != null && a.length > s + 1 - q.base) ||
+ (a = q.growArray()) != null) {
+ int j = (((a.length - 1) & s) << ASHIFT) + ABASE;
+ U.putOrderedObject(a, j, task);
+ U.putOrderedInt(q, QTOP, s + 1);
+ submitted = true;
+ }
+ } finally {
+ U.compareAndSwapInt(q, QLOCK, 1, 0);
+ }
+ if (submitted) {
+ signalWork(ws, q);
+ return;
+ }
+ }
+ move = true; // move on failure
+ }
+ else if (((rs = runState) & RSLOCK) == 0) { // create new queue
+ q = new WorkQueue(this, null);
+ q.hint = r;
+ q.config = k | SHARED_QUEUE;
+ q.scanState = INACTIVE;
+ rs = lockRunState(); // publish index
+ if (rs > 0 && (ws = workQueues) != null &&
+ k < ws.length && ws[k] == null)
+ ws[k] = q; // else terminated
+ unlockRunState(rs, rs & ~RSLOCK);
+ }
+ else
+ move = true; // move if busy
+ if (move)
+ r = ThreadLocalRandom.advanceProbe(r);
}
}
- // external operations on common pool
+ /**
+ * Tries to add the given task to a submission queue at
+ * submitter's current queue. Only the (vastly) most common path
+ * is directly handled in this method, while screening for need
+ * for externalSubmit.
+ *
+ * @param task the task. Caller must ensure non-null.
+ */
+ final void externalPush(ForkJoinTask<?> task) {
+ WorkQueue[] ws; WorkQueue q; int m;
+ int r = ThreadLocalRandom.getProbe();
+ int rs = runState;
+ if ((ws = workQueues) != null && (m = (ws.length - 1)) >= 0 &&
+ (q = ws[m & r & SQMASK]) != null && r != 0 && rs > 0 &&
+ U.compareAndSwapInt(q, QLOCK, 0, 1)) {
+ ForkJoinTask<?>[] a; int am, n, s;
+ if ((a = q.array) != null &&
+ (am = a.length - 1) > (n = (s = q.top) - q.base)) {
+ int j = ((am & s) << ASHIFT) + ABASE;
+ U.putOrderedObject(a, j, task);
+ U.putOrderedInt(q, QTOP, s + 1);
+ U.putOrderedInt(q, QLOCK, 0);
+ if (n <= 1)
+ signalWork(ws, q);
+ return;
+ }
+ U.compareAndSwapInt(q, QLOCK, 1, 0);
+ }
+ externalSubmit(task);
+ }
/**
- * Returns common pool queue for a thread that has submitted at
- * least one task.
+ * Returns common pool queue for an external thread.
*/
static WorkQueue commonSubmitterQueue() {
- ForkJoinPool p; WorkQueue[] ws; int m, z;
- return ((z = ThreadLocalRandom.getProbe()) != 0 &&
- (p = common) != null &&
- (ws = p.workQueues) != null &&
+ ForkJoinPool p = common;
+ int r = ThreadLocalRandom.getProbe();
+ WorkQueue[] ws; int m;
+ return (p != null && (ws = p.workQueues) != null &&
(m = ws.length - 1) >= 0) ?
- ws[m & z & SQMASK] : null;
+ ws[m & r & SQMASK] : null;
}
/**
- * Tries to pop the given task from submitter's queue in common pool.
+ * Performs tryUnpush for an external submitter: Finds queue,
+ * locks if apparently non-empty, validates upon locking, and
+ * adjusts top. Each check can fail but rarely does.
*/
final boolean tryExternalUnpush(ForkJoinTask<?> task) {
- WorkQueue joiner; ForkJoinTask<?>[] a; int m, s;
- WorkQueue[] ws = workQueues;
- int z = ThreadLocalRandom.getProbe();
- boolean popped = false;
- if (ws != null && (m = ws.length - 1) >= 0 &&
- (joiner = ws[z & m & SQMASK]) != null &&
- joiner.base != (s = joiner.top) &&
- (a = joiner.array) != null) {
+ WorkQueue[] ws; WorkQueue w; ForkJoinTask<?>[] a; int m, s;
+ int r = ThreadLocalRandom.getProbe();
+ if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 &&
+ (w = ws[m & r & SQMASK]) != null &&
+ (a = w.array) != null && (s = w.top) != w.base) {
long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
- if (U.getObject(a, j) == task &&
- U.compareAndSwapInt(joiner, QLOCK, 0, 1)) {
- if (joiner.top == s && joiner.array == a &&
+ if (U.compareAndSwapInt(w, QLOCK, 0, 1)) {
+ if (w.top == s && w.array == a &&
+ U.getObject(a, j) == task &&
U.compareAndSwapObject(a, j, task, null)) {
- joiner.top = s - 1;
- popped = true;
+ U.putOrderedInt(w, QTOP, s - 1);
+ U.putOrderedInt(w, QLOCK, 0);
+ return true;
}
- joiner.qlock = 0;
+ U.compareAndSwapInt(w, QLOCK, 1, 0);
}
}
- return popped;
+ return false;
}
+ /**
+ * Performs helpComplete for an external submitter.
+ */
final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
- WorkQueue joiner; int m;
- WorkQueue[] ws = workQueues;
- int j = ThreadLocalRandom.getProbe();
- int s = 0;
- if (ws != null && (m = ws.length - 1) >= 0 &&
- (joiner = ws[j & m & SQMASK]) != null && task != null) {
- int scans = m + m + 1;
- long c = 0L; // for stability check
- j |= 1; // poll odd queues
- for (int k = scans; ; j += 2) {
- WorkQueue q;
- if ((s = task.status) < 0)
- break;
- else if (joiner.externalPopAndExecCC(task)) {
- if (--maxTasks <= 0) {
- s = task.status;
- break;
- }
- k = scans;
- }
- else if ((s = task.status) < 0)
- break;
- else if ((q = ws[j & m]) != null && q.pollAndExecCC(task)) {
- if (--maxTasks <= 0) {
- s = task.status;
- break;
- }
- k = scans;
- }
- else if (--k < 0) {
- if (c == (c = ctl))
- break;
- k = scans;
- }
- }
- }
- return s;
+ WorkQueue[] ws; int n;
+ int r = ThreadLocalRandom.getProbe();
+ return ((ws = workQueues) == null || (n = ws.length) == 0) ? 0 :
+ helpComplete(ws[(n - 1) & r & SQMASK], task, maxTasks);
}
// Exported methods
@@ -2447,7 +2533,7 @@
this(checkParallelism(parallelism),
checkFactory(factory),
handler,
- (asyncMode ? FIFO_QUEUE : LIFO_QUEUE),
+ asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
"ForkJoinPool-" + nextPoolId() + "-worker-");
checkPermission();
}
@@ -2478,8 +2564,7 @@
this.workerNamePrefix = workerNamePrefix;
this.factory = factory;
this.ueh = handler;
- this.mode = (short)mode;
- this.parallelism = (short)parallelism;
+ this.config = (parallelism & SMASK) | mode;
long np = (long)(-parallelism); // offset ctl counts
this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
}
@@ -2624,7 +2709,7 @@
// In previous versions of this class, this method constructed
// a task to run ForkJoinTask.invokeAll, but now external
// invocation of multiple tasks is at least as efficient.
- ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
+ ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
boolean done = false;
try {
@@ -2670,7 +2755,7 @@
*/
public int getParallelism() {
int par;
- return ((par = parallelism) > 0) ? par : 1;
+ return ((par = config & SMASK) > 0) ? par : 1;
}
/**
@@ -2692,7 +2777,7 @@
* @return the number of worker threads
*/
public int getPoolSize() {
- return parallelism + (short)(ctl >>> TC_SHIFT);
+ return (config & SMASK) + (short)(ctl >>> TC_SHIFT);
}
/**
@@ -2702,7 +2787,7 @@
* @return {@code true} if this pool uses async mode
*/
public boolean getAsyncMode() {
- return mode == FIFO_QUEUE;
+ return (config & FIFO_QUEUE) != 0;
}
/**
@@ -2733,7 +2818,7 @@
* @return the number of active threads
*/
public int getActiveThreadCount() {
- int r = parallelism + (int)(ctl >> AC_SHIFT);
+ int r = (config & SMASK) + (int)(ctl >> AC_SHIFT);
return (r <= 0) ? 0 : r; // suppress momentarily negative values
}
@@ -2749,7 +2834,7 @@
* @return {@code true} if all threads are currently idle
*/
public boolean isQuiescent() {
- return parallelism + (int)(ctl >> AC_SHIFT) <= 0;
+ return (config & SMASK) + (int)(ctl >> AC_SHIFT) <= 0;
}
/**
@@ -2764,7 +2849,8 @@
* @return the number of steals
*/
public long getStealCount() {
- long count = stealCount;
+ AtomicLong sc = stealCounter;
+ long count = (sc == null) ? 0L : sc.get();
WorkQueue[] ws; WorkQueue w;
if ((ws = workQueues) != null) {
for (int i = 1; i < ws.length; i += 2) {
@@ -2894,7 +2980,8 @@
public String toString() {
// Use a single pass through workQueues to collect counts
long qt = 0L, qs = 0L; int rc = 0;
- long st = stealCount;
+ AtomicLong sc = stealCounter;
+ long st = (sc == null) ? 0L : sc.get();
long c = ctl;
WorkQueue[] ws; WorkQueue w;
if ((ws = workQueues) != null) {
@@ -2912,16 +2999,16 @@
}
}
}
- int pc = parallelism;
+ int pc = (config & SMASK);
int tc = pc + (short)(c >>> TC_SHIFT);
int ac = pc + (int)(c >> AC_SHIFT);
if (ac < 0) // ignore transient negative
ac = 0;
- String level;
- if ((c & STOP_BIT) != 0)
- level = (tc == 0) ? "Terminated" : "Terminating";
- else
- level = plock < 0 ? "Shutting down" : "Running";
+ int rs = runState;
+ String level = ((rs & TERMINATED) != 0 ? "Terminated" :
+ (rs & STOP) != 0 ? "Terminating" :
+ (rs & SHUTDOWN) != 0 ? "Shutting down" :
+ "Running");
return super.toString() +
"[" + level +
", parallelism = " + pc +
@@ -2983,9 +3070,7 @@
* @return {@code true} if all tasks have completed following shut down
*/
public boolean isTerminated() {
- long c = ctl;
- return ((c & STOP_BIT) != 0L &&
- (short)(c >>> TC_SHIFT) + parallelism <= 0);
+ return (runState & TERMINATED) != 0;
}
/**
@@ -3002,9 +3087,8 @@
* @return {@code true} if terminating but not yet terminated
*/
public boolean isTerminating() {
- long c = ctl;
- return ((c & STOP_BIT) != 0L &&
- (short)(c >>> TC_SHIFT) + parallelism > 0);
+ int rs = runState;
+ return (rs & STOP) != 0 && (rs & TERMINATED) == 0;
}
/**
@@ -3013,7 +3097,7 @@
* @return {@code true} if this pool has been shut down
*/
public boolean isShutdown() {
- return plock < 0;
+ return (runState & SHUTDOWN) != 0;
}
/**
@@ -3090,8 +3174,9 @@
}
found = false;
for (int j = (m + 1) << 2; j >= 0; --j) {
- ForkJoinTask<?> t; WorkQueue q; int b;
- if ((q = ws[r++ & m]) != null && (b = q.base) - q.top < 0) {
+ ForkJoinTask<?> t; WorkQueue q; int b, k;
+ if ((k = r++ & m) <= m && k >= 0 && (q = ws[k]) != null &&
+ (b = q.base) - q.top < 0) {
found = true;
if ((t = q.pollAt(b)) != null)
t.doExec();
@@ -3115,8 +3200,8 @@
* in {@link ForkJoinPool}s.
*
* <p>A {@code ManagedBlocker} provides two methods. Method
- * {@code isReleasable} must return {@code true} if blocking is
- * not necessary. Method {@code block} blocks the current thread
+ * {@link #isReleasable} must return {@code true} if blocking is
+ * not necessary. Method {@link #block} blocks the current thread
* if necessary (perhaps internally invoking {@code isReleasable}
* before actually blocking). These actions are performed by any
* thread invoking {@link ForkJoinPool#managedBlock(ManagedBlocker)}.
@@ -3185,37 +3270,46 @@
}
/**
- * Blocks in accord with the given blocker. If the current thread
- * is a {@link ForkJoinWorkerThread}, this method possibly
- * arranges for a spare thread to be activated if necessary to
- * ensure sufficient parallelism while the current thread is blocked.
+ * Runs the given possibly blocking task. When {@linkplain
+ * ForkJoinTask#inForkJoinPool() running in a ForkJoinPool}, this
+ * method possibly arranges for a spare thread to be activated if
+ * necessary to ensure sufficient parallelism while the current
+ * thread is blocked in {@link ManagedBlocker#block blocker.block()}.
*
- * <p>If the caller is not a {@link ForkJoinTask}, this method is
+ * <p>This method repeatedly calls {@code blocker.isReleasable()} and
+ * {@code blocker.block()} until either method returns {@code true}.
+ * Every call to {@code blocker.block()} is preceded by a call to
+ * {@code blocker.isReleasable()} that returned {@code false}.
+ *
+ * <p>If not running in a ForkJoinPool, this method is
* behaviorally equivalent to
* <pre> {@code
* while (!blocker.isReleasable())
* if (blocker.block())
- * return;
- * }</pre>
+ * break;}</pre>
*
- * If the caller is a {@code ForkJoinTask}, then the pool may
- * first be expanded to ensure parallelism, and later adjusted.
+ * If running in a ForkJoinPool, the pool may first be expanded to
+ * ensure sufficient parallelism available during the call to
+ * {@code blocker.block()}.
*
- * @param blocker the blocker
- * @throws InterruptedException if blocker.block did so
+ * @param blocker the blocker task
+ * @throws InterruptedException if {@code blocker.block()} did so
*/
public static void managedBlock(ManagedBlocker blocker)
throws InterruptedException {
+ ForkJoinPool p;
+ ForkJoinWorkerThread wt;
Thread t = Thread.currentThread();
- if (t instanceof ForkJoinWorkerThread) {
- ForkJoinPool p = ((ForkJoinWorkerThread)t).pool;
+ if ((t instanceof ForkJoinWorkerThread) &&
+ (p = (wt = (ForkJoinWorkerThread)t).pool) != null) {
+ WorkQueue w = wt.workQueue;
while (!blocker.isReleasable()) {
- if (p.tryCompensate(p.ctl)) {
+ if (p.tryCompensate(w)) {
try {
do {} while (!blocker.isReleasable() &&
!blocker.block());
} finally {
- p.incrementActiveCount();
+ U.getAndAddLong(p, CTL, AC_UNIT);
}
break;
}
@@ -3241,15 +3335,18 @@
// Unsafe mechanics
private static final sun.misc.Unsafe U;
+ private static final int ABASE;
+ private static final int ASHIFT;
private static final long CTL;
+ private static final long RUNSTATE;
+ private static final long STEALCOUNTER;
private static final long PARKBLOCKER;
- private static final int ABASE;
- private static final int ASHIFT;
- private static final long STEALCOUNT;
- private static final long PLOCK;
- private static final long INDEXSEED;
- private static final long QBASE;
+ private static final long QTOP;
private static final long QLOCK;
+ private static final long QSCANSTATE;
+ private static final long QPARKER;
+ private static final long QCURRENTSTEAL;
+ private static final long QCURRENTJOIN;
static {
// initialize field offsets for CAS etc
@@ -3258,20 +3355,26 @@
Class<?> k = ForkJoinPool.class;
CTL = U.objectFieldOffset
(k.getDeclaredField("ctl"));
- STEALCOUNT = U.objectFieldOffset
- (k.getDeclaredField("stealCount"));
- PLOCK = U.objectFieldOffset
- (k.getDeclaredField("plock"));
- INDEXSEED = U.objectFieldOffset
- (k.getDeclaredField("indexSeed"));
+ RUNSTATE = U.objectFieldOffset
+ (k.getDeclaredField("runState"));
+ STEALCOUNTER = U.objectFieldOffset
+ (k.getDeclaredField("stealCounter"));
Class<?> tk = Thread.class;
PARKBLOCKER = U.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
Class<?> wk = WorkQueue.class;
- QBASE = U.objectFieldOffset
- (wk.getDeclaredField("base"));
+ QTOP = U.objectFieldOffset
+ (wk.getDeclaredField("top"));
QLOCK = U.objectFieldOffset
(wk.getDeclaredField("qlock"));
+ QSCANSTATE = U.objectFieldOffset
+ (wk.getDeclaredField("scanState"));
+ QPARKER = U.objectFieldOffset
+ (wk.getDeclaredField("parker"));
+ QCURRENTSTEAL = U.objectFieldOffset
+ (wk.getDeclaredField("currentSteal"));
+ QCURRENTJOIN = U.objectFieldOffset
+ (wk.getDeclaredField("currentJoin"));
Class<?> ak = ForkJoinTask[].class;
ABASE = U.arrayBaseOffset(ak);
int scale = U.arrayIndexScale(ak);
@@ -3282,6 +3385,7 @@
throw new Error(e);
}
+ commonMaxSpares = DEFAULT_COMMON_MAX_SPARES;
defaultForkJoinWorkerThreadFactory =
new DefaultForkJoinWorkerThreadFactory();
modifyThreadPermission = new RuntimePermission("modifyThread");
@@ -3289,7 +3393,7 @@
common = java.security.AccessController.doPrivileged
(new java.security.PrivilegedAction<ForkJoinPool>() {
public ForkJoinPool run() { return makeCommonPool(); }});
- int par = common.parallelism; // report 1 even if threads disabled
+ int par = common.config & SMASK; // report 1 even if threads disabled
commonParallelism = par > 0 ? par : 1;
}
diff --git a/src/share/classes/java/util/concurrent/ForkJoinTask.java b/src/share/classes/java/util/concurrent/ForkJoinTask.java
index 936bfc2..4439c24 100644
--- a/src/share/classes/java/util/concurrent/ForkJoinTask.java
+++ b/src/share/classes/java/util/concurrent/ForkJoinTask.java
@@ -297,15 +297,22 @@
}
/**
- * Tries to set SIGNAL status unless already completed. Used by
- * ForkJoinPool. Other variants are directly incorporated into
- * externalAwaitDone etc.
+ * If not done, sets SIGNAL status and performs Object.wait(timeout).
+ * This task may or may not be done on exit. Ignores interrupts.
*
- * @return true if successful
+ * @param timeout using Object.wait conventions.
*/
- final boolean trySetSignal() {
- int s = status;
- return s >= 0 && U.compareAndSwapInt(this, STATUS, s, s | SIGNAL);
+ final void internalWait(long timeout) {
+ int s;
+ if ((s = status) >= 0 && // force completer to issue notify
+ U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+ synchronized (this) {
+ if (status >= 0)
+ try { wait(timeout); } catch (InterruptedException ie) { }
+ else
+ notifyAll();
+ }
+ }
}
/**
@@ -313,35 +320,29 @@
* @return status upon completion
*/
private int externalAwaitDone() {
- int s;
- ForkJoinPool cp = ForkJoinPool.common;
- if ((s = status) >= 0) {
- if (cp != null) {
- if (this instanceof CountedCompleter)
- s = cp.externalHelpComplete((CountedCompleter<?>)this, Integer.MAX_VALUE);
- else if (cp.tryExternalUnpush(this))
- s = doExec();
- }
- if (s >= 0 && (s = status) >= 0) {
- boolean interrupted = false;
- do {
- if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
- synchronized (this) {
- if (status >= 0) {
- try {
- wait();
- } catch (InterruptedException ie) {
- interrupted = true;
- }
+ int s = ((this instanceof CountedCompleter) ? // try helping
+ ForkJoinPool.common.externalHelpComplete(
+ (CountedCompleter<?>)this, 0) :
+ ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0);
+ if (s >= 0 && (s = status) >= 0) {
+ boolean interrupted = false;
+ do {
+ if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+ synchronized (this) {
+ if (status >= 0) {
+ try {
+ wait(0L);
+ } catch (InterruptedException ie) {
+ interrupted = true;
}
- else
- notifyAll();
}
+ else
+ notifyAll();
}
- } while ((s = status) >= 0);
- if (interrupted)
- Thread.currentThread().interrupt();
- }
+ }
+ } while ((s = status) >= 0);
+ if (interrupted)
+ Thread.currentThread().interrupt();
}
return s;
}
@@ -351,22 +352,22 @@
*/
private int externalInterruptibleAwaitDone() throws InterruptedException {
int s;
- ForkJoinPool cp = ForkJoinPool.common;
if (Thread.interrupted())
throw new InterruptedException();
- if ((s = status) >= 0 && cp != null) {
- if (this instanceof CountedCompleter)
- cp.externalHelpComplete((CountedCompleter<?>)this, Integer.MAX_VALUE);
- else if (cp.tryExternalUnpush(this))
- doExec();
- }
- while ((s = status) >= 0) {
- if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
- synchronized (this) {
- if (status >= 0)
- wait();
- else
- notifyAll();
+ if ((s = status) >= 0 &&
+ (s = ((this instanceof CountedCompleter) ?
+ ForkJoinPool.common.externalHelpComplete(
+ (CountedCompleter<?>)this, 0) :
+ ForkJoinPool.common.tryExternalUnpush(this) ? doExec() :
+ 0)) >= 0) {
+ while ((s = status) >= 0) {
+ if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+ synchronized (this) {
+ if (status >= 0)
+ wait(0L);
+ else
+ notifyAll();
+ }
}
}
}
@@ -386,7 +387,7 @@
((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
(w = (wt = (ForkJoinWorkerThread)t).workQueue).
tryUnpush(this) && (s = doExec()) < 0 ? s :
- wt.pool.awaitJoin(w, this) :
+ wt.pool.awaitJoin(w, this, 0L) :
externalAwaitDone();
}
@@ -399,7 +400,8 @@
int s; Thread t; ForkJoinWorkerThread wt;
return (s = doExec()) < 0 ? s :
((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
- (wt = (ForkJoinWorkerThread)t).pool.awaitJoin(wt.workQueue, this) :
+ (wt = (ForkJoinWorkerThread)t).pool.
+ awaitJoin(wt.workQueue, this, 0L) :
externalAwaitDone();
}
@@ -577,7 +579,7 @@
Throwable ex;
if (e == null || (ex = e.ex) == null)
return null;
- if (false && e.thrower != Thread.currentThread().getId()) {
+ if (e.thrower != Thread.currentThread().getId()) {
Class<? extends Throwable> ec = ex.getClass();
try {
Constructor<?> noArgCtor = null;
@@ -587,13 +589,17 @@
Class<?>[] ps = c.getParameterTypes();
if (ps.length == 0)
noArgCtor = c;
- else if (ps.length == 1 && ps[0] == Throwable.class)
- return (Throwable)(c.newInstance(ex));
+ else if (ps.length == 1 && ps[0] == Throwable.class) {
+ Throwable wx = (Throwable)c.newInstance(ex);
+ return (wx == null) ? ex : wx;
+ }
}
if (noArgCtor != null) {
Throwable wx = (Throwable)(noArgCtor.newInstance());
- wx.initCause(ex);
- return wx;
+ if (wx != null) {
+ wx.initCause(ex);
+ return wx;
+ }
}
} catch (Exception ignore) {
}
@@ -1017,67 +1023,40 @@
*/
public final V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
+ int s;
+ long nanos = unit.toNanos(timeout);
if (Thread.interrupted())
throw new InterruptedException();
- // Messy in part because we measure in nanosecs, but wait in millisecs
- int s; long ms;
- long ns = unit.toNanos(timeout);
- ForkJoinPool cp;
- if ((s = status) >= 0 && ns > 0L) {
- long deadline = System.nanoTime() + ns;
- ForkJoinPool p = null;
- ForkJoinPool.WorkQueue w = null;
+ if ((s = status) >= 0 && nanos > 0L) {
+ long d = System.nanoTime() + nanos;
+ long deadline = (d == 0L) ? 1L : d; // avoid 0
Thread t = Thread.currentThread();
if (t instanceof ForkJoinWorkerThread) {
ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
- p = wt.pool;
- w = wt.workQueue;
- p.helpJoinOnce(w, this); // no retries on failure
+ s = wt.pool.awaitJoin(wt.workQueue, this, deadline);
}
- else if ((cp = ForkJoinPool.common) != null) {
- if (this instanceof CountedCompleter)
- cp.externalHelpComplete((CountedCompleter<?>)this, Integer.MAX_VALUE);
- else if (cp.tryExternalUnpush(this))
- doExec();
- }
- boolean canBlock = false;
- boolean interrupted = false;
- try {
- while ((s = status) >= 0) {
- if (w != null && w.qlock < 0)
- cancelIgnoringExceptions(this);
- else if (!canBlock) {
- if (p == null || p.tryCompensate(p.ctl))
- canBlock = true;
- }
- else {
- if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
- U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
- synchronized (this) {
- if (status >= 0) {
- try {
- wait(ms);
- } catch (InterruptedException ie) {
- if (p == null)
- interrupted = true;
- }
- }
- else
- notifyAll();
- }
+ else if ((s = ((this instanceof CountedCompleter) ?
+ ForkJoinPool.common.externalHelpComplete(
+ (CountedCompleter<?>)this, 0) :
+ ForkJoinPool.common.tryExternalUnpush(this) ?
+ doExec() : 0)) >= 0) {
+ long ns, ms; // measure in nanosecs, but wait in millisecs
+ while ((s = status) >= 0 &&
+ (ns = deadline - System.nanoTime()) > 0L) {
+ if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
+ U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+ synchronized (this) {
+ if (status >= 0)
+ wait(ms); // OK to throw InterruptedException
+ else
+ notifyAll();
}
- if ((s = status) < 0 || interrupted ||
- (ns = deadline - System.nanoTime()) <= 0L)
- break;
}
}
- } finally {
- if (p != null && canBlock)
- p.incrementActiveCount();
}
- if (interrupted)
- throw new InterruptedException();
}
+ if (s >= 0)
+ s = status;
if ((s &= DONE_MASK) != NORMAL) {
Throwable ex;
if (s == CANCELLED)
diff --git a/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java b/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java
index 404c47c..8723f0a 100644
--- a/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java
+++ b/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java
@@ -66,7 +66,7 @@
* owning thread.
*
* Support for (non-public) subclass InnocuousForkJoinWorkerThread
- * requires that we break quite a lot of encapulation (via Unsafe)
+ * requires that we break quite a lot of encapsulation (via Unsafe)
* both here and in the subclass to access and set Thread fields.
*/
@@ -118,7 +118,7 @@
* @return the index number
*/
public int getPoolIndex() {
- return workQueue.poolIndex >>> 1; // ignore odd/even tag bit
+ return workQueue.getPoolIndex();
}
/**
@@ -171,7 +171,7 @@
}
/**
- * Erases ThreadLocals by nulling out Thread maps
+ * Erases ThreadLocals by nulling out Thread maps.
*/
final void eraseThreadLocals() {
U.putObject(this, THREADLOCALS, null);
@@ -246,8 +246,8 @@
/**
* Returns a new group with the system ThreadGroup (the
- * topmost, parentless group) as parent. Uses Unsafe to
- * traverse Thread group and ThreadGroup parent fields.
+ * topmost, parent-less group) as parent. Uses Unsafe to
+ * traverse Thread.group and ThreadGroup.parent fields.
*/
private static ThreadGroup createThreadGroup() {
try {
@@ -274,4 +274,3 @@
}
}
-
diff --git a/src/share/classes/java/util/logging/FileHandler.java b/src/share/classes/java/util/logging/FileHandler.java
index 9699b72..2c3bb50 100644
--- a/src/share/classes/java/util/logging/FileHandler.java
+++ b/src/share/classes/java/util/logging/FileHandler.java
@@ -402,6 +402,14 @@
openFiles();
}
+ private boolean isParentWritable(Path path) {
+ Path parent = path.getParent();
+ if (parent == null) {
+ parent = path.toAbsolutePath().getParent();
+ }
+ return parent != null && Files.isWritable(parent);
+ }
+
/**
* Open the set of output files, based on the configured
* instance variables.
@@ -458,7 +466,7 @@
// Note that this is a situation that may happen,
// but not too frequently.
if (Files.isRegularFile(lockFilePath, LinkOption.NOFOLLOW_LINKS)
- && Files.isWritable(lockFilePath.getParent())) {
+ && isParentWritable(lockFilePath)) {
try {
channel = FileChannel.open(lockFilePath,
WRITE, APPEND);
diff --git a/src/share/classes/javax/crypto/Cipher.java b/src/share/classes/javax/crypto/Cipher.java
index ffcc7cf..9593540 100644
--- a/src/share/classes/javax/crypto/Cipher.java
+++ b/src/share/classes/javax/crypto/Cipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -167,6 +167,11 @@
private static final Debug debug =
Debug.getInstance("jca", "Cipher");
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("cipher");
+
/**
* Constant used to initialize cipher to encryption mode.
*/
@@ -1110,6 +1115,21 @@
}
}
+ private static String getOpmodeString(int opmode) {
+ switch (opmode) {
+ case ENCRYPT_MODE:
+ return "encryption";
+ case DECRYPT_MODE:
+ return "decryption";
+ case WRAP_MODE:
+ return "key wrapping";
+ case UNWRAP_MODE:
+ return "key unwrapping";
+ default:
+ return "";
+ }
+ }
+
/**
* Initializes this cipher with a key.
*
@@ -1235,6 +1255,12 @@
initialized = true;
this.opmode = opmode;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Cipher." + transformation + " " +
+ getOpmodeString(opmode) + " algorithm from: " +
+ this.provider.getName());
+ }
}
/**
@@ -1372,6 +1398,12 @@
initialized = true;
this.opmode = opmode;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Cipher." + transformation + " " +
+ getOpmodeString(opmode) + " algorithm from: " +
+ this.provider.getName());
+ }
}
/**
@@ -1509,6 +1541,12 @@
initialized = true;
this.opmode = opmode;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Cipher." + transformation + " " +
+ getOpmodeString(opmode) + " algorithm from: " +
+ this.provider.getName());
+ }
}
/**
@@ -1693,6 +1731,12 @@
initialized = true;
this.opmode = opmode;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Cipher." + transformation + " " +
+ getOpmodeString(opmode) + " algorithm from: " +
+ this.provider.getName());
+ }
}
/**
diff --git a/src/share/classes/javax/crypto/KeyAgreement.java b/src/share/classes/javax/crypto/KeyAgreement.java
index 70221aa..2c24470 100644
--- a/src/share/classes/javax/crypto/KeyAgreement.java
+++ b/src/share/classes/javax/crypto/KeyAgreement.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -78,6 +78,11 @@
private static final Debug debug =
Debug.getInstance("jca", "KeyAgreement");
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("keyagreement");
+
// The provider
private Provider provider;
@@ -468,6 +473,11 @@
throw new InvalidKeyException(e);
}
}
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
}
/**
@@ -524,6 +534,11 @@
} else {
chooseProvider(I_PARAMS, key, params, random);
}
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
}
/**
diff --git a/src/share/classes/javax/crypto/KeyGenerator.java b/src/share/classes/javax/crypto/KeyGenerator.java
index 030207e..9da64e9 100644
--- a/src/share/classes/javax/crypto/KeyGenerator.java
+++ b/src/share/classes/javax/crypto/KeyGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
import sun.security.jca.*;
import sun.security.jca.GetInstance.Instance;
+import sun.security.util.Debug;
/**
* This class provides the functionality of a secret (symmetric) key generator.
@@ -108,6 +109,11 @@
public class KeyGenerator {
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("keygenerator");
+
// see java.security.KeyPairGenerator for failover notes
private final static int I_NONE = 1;
@@ -145,6 +151,11 @@
this.spi = keyGenSpi;
this.provider = provider;
this.algorithm = algorithm;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
}
private KeyGenerator(String algorithm) throws NoSuchAlgorithmException {
@@ -158,6 +169,11 @@
throw new NoSuchAlgorithmException
(algorithm + " KeyGenerator not available");
}
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
}
/**
diff --git a/src/share/classes/javax/crypto/Mac.java b/src/share/classes/javax/crypto/Mac.java
index d0e241d..8a497da 100644
--- a/src/share/classes/javax/crypto/Mac.java
+++ b/src/share/classes/javax/crypto/Mac.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -77,6 +77,11 @@
private static final Debug debug =
Debug.getInstance("jca", "Mac");
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("mac");
+
// The provider
private Provider provider;
@@ -413,6 +418,11 @@
throw new InvalidKeyException("init() failed", e);
}
initialized = true;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Mac." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
}
/**
@@ -435,6 +445,11 @@
chooseProvider(key, params);
}
initialized = true;
+
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Mac." + algorithm + " algorithm from: " +
+ this.provider.getName());
+ }
}
/**
diff --git a/src/share/classes/sun/awt/datatransfer/DataTransferer.java b/src/share/classes/sun/awt/datatransfer/DataTransferer.java
index c5a7f59..b21dab6 100644
--- a/src/share/classes/sun/awt/datatransfer/DataTransferer.java
+++ b/src/share/classes/sun/awt/datatransfer/DataTransferer.java
@@ -2895,6 +2895,14 @@
return comp;
}
+ if (flavor1.isFlavorTextType()) {
+ return 1;
+ }
+
+ if (flavor2.isFlavorTextType()) {
+ return -1;
+ }
+
// Next, look for application/x-java-* types. Prefer unknown
// MIME types because if the user provides his own data flavor,
// it will likely be the most descriptive one.
diff --git a/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java b/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java
index 1c66bf5..2390639 100644
--- a/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java
+++ b/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java
@@ -523,13 +523,6 @@
valid = false;
}
- // get the mechanism token
- byte[] mechToken = initToken.getMechToken();
- if (mechToken == null) {
- throw new GSSException(GSSException.FAILURE, -1,
- "mechToken is missing");
- }
-
/*
* Select the best match between the list of mechs
* that the initiator requested and the list that
@@ -545,7 +538,19 @@
internal_mech = mech_wanted;
// get the token for mechanism
- byte[] accept_token = GSS_acceptSecContext(mechToken);
+ byte[] accept_token;
+
+ if (mechList[0].equals(mech_wanted)) {
+ // get the mechanism token
+ byte[] mechToken = initToken.getMechToken();
+ if (mechToken == null) {
+ throw new GSSException(GSSException.FAILURE, -1,
+ "mechToken is missing");
+ }
+ accept_token = GSS_acceptSecContext(mechToken);
+ } else {
+ accept_token = null;
+ }
// verify MIC
if (!GSSUtil.useMSInterop() && valid) {
@@ -594,9 +599,27 @@
retVal = targToken.getEncoded();
} else if (state == STATE_IN_PROCESS) {
+ // read data
+ byte[] token = new byte[is.available()];
+ SpNegoToken.readFully(is, token);
+ if (DEBUG) {
+ System.out.println("SpNegoContext.acceptSecContext: " +
+ "receiving token = " +
+ SpNegoToken.getHexBytes(token));
+ }
+
+ // read the SPNEGO token
+ // token will be validated when parsing
+ NegTokenTarg inputToken = new NegTokenTarg(token);
+
+ if (DEBUG) {
+ System.out.println("SpNegoContext.acceptSecContext: " +
+ "received token of type = " +
+ SpNegoToken.getTokenName(inputToken.getType()));
+ }
+
// read the token
- byte[] client_token = new byte[is.available()];
- SpNegoToken.readFully(is, client_token);
+ byte[] client_token = inputToken.getResponseToken();
byte[] accept_token = GSS_acceptSecContext(client_token);
if (accept_token == null) {
valid = false;
@@ -1055,7 +1078,7 @@
* This is only valid on the acceptor side of the context.
* @return GSSCredentialSpi object for the delegated credential
* @exception GSSException
- * @see GSSContext#getDelegCredState
+ * @see GSSContext#getCredDelegState
*/
public final GSSCredentialSpi getDelegCred() throws GSSException {
if (state != STATE_IN_PROCESS && state != STATE_DONE)
diff --git a/src/share/classes/sun/security/tools/keytool/Resources.java b/src/share/classes/sun/security/tools/keytool/Resources.java
index 6199927..73eac26 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources.java
@@ -336,7 +336,7 @@
{"New.prompt.", "New {0}: "},
{"Passwords.must.differ", "Passwords must differ"},
{"Re.enter.new.prompt.", "Re-enter new {0}: "},
- {"Re.enter.passpword.", "Re-enter password: "},
+ {"Re.enter.password.", "Re-enter password: "},
{"Re.enter.new.password.", "Re-enter new password: "},
{"They.don.t.match.Try.again", "They don't match. Try again"},
{"Enter.prompt.alias.name.", "Enter {0} alias name: "},
diff --git a/src/share/classes/sun/security/tools/keytool/Resources_de.java b/src/share/classes/sun/security/tools/keytool/Resources_de.java
index 2a80245..a024795 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources_de.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources_de.java
@@ -336,7 +336,7 @@
{"New.prompt.", "Neues {0}: "},
{"Passwords.must.differ", "Kennw\u00F6rter m\u00FCssen sich unterscheiden"},
{"Re.enter.new.prompt.", "Neues {0} erneut eingeben: "},
- {"Re.enter.passpword.", "Geben Sie das Kennwort erneut ein: "},
+ {"Re.enter.password.", "Geben Sie das Kennwort erneut ein: "},
{"Re.enter.new.password.", "Neues Kennwort erneut eingeben: "},
{"They.don.t.match.Try.again", "Keine \u00DCbereinstimmung. Wiederholen Sie den Vorgang"},
{"Enter.prompt.alias.name.", "{0}-Aliasnamen eingeben: "},
diff --git a/src/share/classes/sun/security/tools/keytool/Resources_es.java b/src/share/classes/sun/security/tools/keytool/Resources_es.java
index 4c0bd34..5348d1a 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources_es.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources_es.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -336,7 +336,7 @@
{"New.prompt.", "Nuevo {0}: "},
{"Passwords.must.differ", "Las contrase\u00F1as deben ser distintas"},
{"Re.enter.new.prompt.", "Vuelva a escribir el nuevo {0}: "},
- {"Re.enter.passpword.", "Vuelva a introducir la contrase\u00F1a: "},
+ {"Re.enter.password.", "Vuelva a introducir la contrase\u00F1a: "},
{"Re.enter.new.password.", "Volver a escribir la contrase\u00F1a nueva: "},
{"They.don.t.match.Try.again", "No coinciden. Int\u00E9ntelo de nuevo"},
{"Enter.prompt.alias.name.", "Escriba el nombre de alias de {0}: "},
diff --git a/src/share/classes/sun/security/tools/keytool/Resources_fr.java b/src/share/classes/sun/security/tools/keytool/Resources_fr.java
index 6ba2985..6b22844 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources_fr.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources_fr.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -336,7 +336,7 @@
{"New.prompt.", "Nouveau {0} : "},
{"Passwords.must.differ", "Les mots de passe doivent diff\u00E9rer"},
{"Re.enter.new.prompt.", "Indiquez encore le nouveau {0} : "},
- {"Re.enter.passpword.", "R\u00E9p\u00E9tez le mot de passe : "},
+ {"Re.enter.password.", "R\u00E9p\u00E9tez le mot de passe : "},
{"Re.enter.new.password.", "Ressaisissez le nouveau mot de passe : "},
{"They.don.t.match.Try.again", "Ils sont diff\u00E9rents. R\u00E9essayez."},
{"Enter.prompt.alias.name.", "Indiquez le nom d''alias {0} : "},
diff --git a/src/share/classes/sun/security/tools/keytool/Resources_it.java b/src/share/classes/sun/security/tools/keytool/Resources_it.java
index 68b64ce..2a49fe6 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources_it.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources_it.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -336,7 +336,7 @@
{"New.prompt.", "Nuova {0}: "},
{"Passwords.must.differ", "Le password non devono coincidere"},
{"Re.enter.new.prompt.", "Reimmettere un nuovo valore per {0}: "},
- {"Re.enter.passpword.", "Reimmettere la password: "},
+ {"Re.enter.password.", "Reimmettere la password: "},
{"Re.enter.new.password.", "Immettere nuovamente la nuova password: "},
{"They.don.t.match.Try.again", "Non corrispondono. Riprovare."},
{"Enter.prompt.alias.name.", "Immettere nome alias {0}: "},
diff --git a/src/share/classes/sun/security/tools/keytool/Resources_ja.java b/src/share/classes/sun/security/tools/keytool/Resources_ja.java
index 5f5ee09..d910203 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources_ja.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources_ja.java
@@ -248,7 +248,7 @@
"\u65E2\u5B58\u306E\u30A8\u30F3\u30C8\u30EA\u306E\u5225\u540D{0}\u304C\u5B58\u5728\u3057\u3066\u3044\u307E\u3059\u3002\u4E0A\u66F8\u304D\u3057\u307E\u3059\u304B\u3002[\u3044\u3044\u3048]: "},
{"Too.many.failures.try.later", "\u969C\u5BB3\u304C\u591A\u3059\u304E\u307E\u3059 - \u5F8C\u3067\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044"},
{"Certification.request.stored.in.file.filename.",
- "\u8A3C\u660E\u66F8\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u30D5\u30A1\u30A4\u30EB<{0}>\u306B\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F"},
+ "\u8A8D\u8A3C\u30EA\u30AF\u30A8\u30B9\u30C8\u304C\u30D5\u30A1\u30A4\u30EB<{0}>\u306B\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F"},
{"Submit.this.to.your.CA", "\u3053\u308C\u3092CA\u306B\u63D0\u51FA\u3057\u3066\u304F\u3060\u3055\u3044"},
{"if.alias.not.specified.destalias.and.srckeypass.must.not.be.specified",
"\u5225\u540D\u3092\u6307\u5B9A\u3057\u306A\u3044\u5834\u5408\u3001\u51FA\u529B\u5148\u30AD\u30FC\u30B9\u30C8\u30A2\u306E\u5225\u540D\u304A\u3088\u3073\u30BD\u30FC\u30B9\u30FB\u30AD\u30FC\u30B9\u30C8\u30A2\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u6307\u5B9A\u3067\u304D\u307E\u305B\u3093"},
@@ -336,7 +336,7 @@
{"New.prompt.", "\u65B0\u898F{0}: "},
{"Passwords.must.differ", "\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u7570\u306A\u3063\u3066\u3044\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059"},
{"Re.enter.new.prompt.", "\u65B0\u898F{0}\u3092\u518D\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044: "},
- {"Re.enter.passpword.", "\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u518D\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044: "},
+ {"Re.enter.password.", "\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u518D\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044: "},
{"Re.enter.new.password.", "\u65B0\u898F\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u518D\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044: "},
{"They.don.t.match.Try.again", "\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u3082\u3046\u4E00\u5EA6\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044"},
{"Enter.prompt.alias.name.", "{0}\u306E\u5225\u540D\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044: "},
diff --git a/src/share/classes/sun/security/tools/keytool/Resources_ko.java b/src/share/classes/sun/security/tools/keytool/Resources_ko.java
index d0bed5c..40ede29 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources_ko.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources_ko.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -336,7 +336,7 @@
{"New.prompt.", "\uC0C8 {0}: "},
{"Passwords.must.differ", "\uBE44\uBC00\uBC88\uD638\uB294 \uB2EC\uB77C\uC57C \uD569\uB2C8\uB2E4."},
{"Re.enter.new.prompt.", "\uC0C8 {0} \uB2E4\uC2DC \uC785\uB825: "},
- {"Re.enter.passpword.", "\uBE44\uBC00\uBC88\uD638 \uB2E4\uC2DC \uC785\uB825: "},
+ {"Re.enter.password.", "\uBE44\uBC00\uBC88\uD638 \uB2E4\uC2DC \uC785\uB825: "},
{"Re.enter.new.password.", "\uC0C8 \uBE44\uBC00\uBC88\uD638 \uB2E4\uC2DC \uC785\uB825: "},
{"They.don.t.match.Try.again", "\uC77C\uCE58\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC2ED\uC2DC\uC624."},
{"Enter.prompt.alias.name.", "{0} \uBCC4\uCE6D \uC774\uB984 \uC785\uB825: "},
diff --git a/src/share/classes/sun/security/tools/keytool/Resources_pt_BR.java b/src/share/classes/sun/security/tools/keytool/Resources_pt_BR.java
index 2f6b6ee..0b976a3 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources_pt_BR.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources_pt_BR.java
@@ -336,7 +336,7 @@
{"New.prompt.", "Nova {0}: "},
{"Passwords.must.differ", "As senhas devem ser diferentes"},
{"Re.enter.new.prompt.", "Informe novamente a nova {0}: "},
- {"Re.enter.passpword.", "Redigite a senha: "},
+ {"Re.enter.password.", "Redigite a senha: "},
{"Re.enter.new.password.", "Informe novamente a nova senha: "},
{"They.don.t.match.Try.again", "Elas n\u00E3o correspondem. Tente novamente"},
{"Enter.prompt.alias.name.", "Informe o nome do alias {0}: "},
diff --git a/src/share/classes/sun/security/tools/keytool/Resources_sv.java b/src/share/classes/sun/security/tools/keytool/Resources_sv.java
index effa0d6..c6b4a84 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources_sv.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources_sv.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -336,7 +336,7 @@
{"New.prompt.", "Nytt {0}: "},
{"Passwords.must.differ", "L\u00F6senorden m\u00E5ste vara olika"},
{"Re.enter.new.prompt.", "Ange nytt {0} igen: "},
- {"Re.enter.passpword.", "Ange l\u00F6senord igen: "},
+ {"Re.enter.password.", "Ange l\u00F6senord igen: "},
{"Re.enter.new.password.", "Ange det nya l\u00F6senordet igen: "},
{"They.don.t.match.Try.again", "De matchar inte. F\u00F6rs\u00F6k igen"},
{"Enter.prompt.alias.name.", "Ange aliasnamn f\u00F6r {0}: "},
diff --git a/src/share/classes/sun/security/tools/keytool/Resources_zh_CN.java b/src/share/classes/sun/security/tools/keytool/Resources_zh_CN.java
index 99f85df..6ae574e 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources_zh_CN.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources_zh_CN.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -336,7 +336,7 @@
{"New.prompt.", "\u65B0{0}: "},
{"Passwords.must.differ", "\u53E3\u4EE4\u4E0D\u80FD\u76F8\u540C"},
{"Re.enter.new.prompt.", "\u91CD\u65B0\u8F93\u5165\u65B0{0}: "},
- {"Re.enter.passpword.", "\u518D\u6B21\u8F93\u5165\u53E3\u4EE4: "},
+ {"Re.enter.password.", "\u518D\u6B21\u8F93\u5165\u53E3\u4EE4: "},
{"Re.enter.new.password.", "\u518D\u6B21\u8F93\u5165\u65B0\u53E3\u4EE4: "},
{"They.don.t.match.Try.again", "\u5B83\u4EEC\u4E0D\u5339\u914D\u3002\u8BF7\u91CD\u8BD5"},
{"Enter.prompt.alias.name.", "\u8F93\u5165{0}\u522B\u540D: "},
diff --git a/src/share/classes/sun/security/tools/keytool/Resources_zh_TW.java b/src/share/classes/sun/security/tools/keytool/Resources_zh_TW.java
index 9f6ec38..1f0bb68 100644
--- a/src/share/classes/sun/security/tools/keytool/Resources_zh_TW.java
+++ b/src/share/classes/sun/security/tools/keytool/Resources_zh_TW.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -336,7 +336,7 @@
{"New.prompt.", "\u65B0 {0}: "},
{"Passwords.must.differ", "\u5FC5\u9808\u662F\u4E0D\u540C\u7684\u5BC6\u78BC"},
{"Re.enter.new.prompt.", "\u91CD\u65B0\u8F38\u5165\u65B0 {0}: "},
- {"Re.enter.passpword.", "\u91CD\u65B0\u8F38\u5165\u5BC6\u78BC:"},
+ {"Re.enter.password.", "\u91CD\u65B0\u8F38\u5165\u5BC6\u78BC:"},
{"Re.enter.new.password.", "\u91CD\u65B0\u8F38\u5165\u65B0\u5BC6\u78BC: "},
{"They.don.t.match.Try.again", "\u5B83\u5011\u4E0D\u76F8\u7B26\u3002\u8ACB\u91CD\u8A66"},
{"Enter.prompt.alias.name.", "\u8F38\u5165 {0} \u5225\u540D\u540D\u7A31: "},
diff --git a/src/share/classes/sun/security/util/Debug.java b/src/share/classes/sun/security/util/Debug.java
index f4005a4..8dd0c3b 100644
--- a/src/share/classes/sun/security/util/Debug.java
+++ b/src/share/classes/sun/security/util/Debug.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -104,7 +104,15 @@
System.err.println("codebase=<URL>");
System.err.println(" only dump output if specified codebase");
System.err.println(" is being checked");
-
+ System.err.println();
+ System.err.println("The following can be used with provider:");
+ System.err.println();
+ System.err.println("engine=<engines>");
+ System.err.println(" only dump output for the specified list");
+ System.err.println(" of JCA engines. Supported values:");
+ System.err.println(" Cipher, KeyAgreement, KeyGenerator,");
+ System.err.println(" KeyPairGenerator, KeyStore, Mac,");
+ System.err.println(" MessageDigest, SecureRandom, Signature.");
System.err.println();
System.err.println("Note: Separate multiple options with a comma");
System.exit(0);
diff --git a/src/share/classes/sun/text/resources/FormatData.java b/src/share/classes/sun/text/resources/FormatData.java
index 971177f..bcb328d 100644
--- a/src/share/classes/sun/text/resources/FormatData.java
+++ b/src/share/classes/sun/text/resources/FormatData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -154,18 +154,18 @@
},
{ "MonthNarrows",
new String[] {
- "J",
- "F",
- "M",
- "A",
- "M",
- "J",
- "J",
- "A",
- "S",
- "O",
- "N",
- "D",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
"",
}
},
diff --git a/src/share/classes/sun/text/resources/en/FormatData_en.java b/src/share/classes/sun/text/resources/en/FormatData_en.java
index d51c9f3..85ae55d 100644
--- a/src/share/classes/sun/text/resources/en/FormatData_en.java
+++ b/src/share/classes/sun/text/resources/en/FormatData_en.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -53,6 +53,23 @@
// define this method as follows:
// return new Object[][] { };
return new Object[][] {
+ { "MonthNarrows",
+ new String[] {
+ "J",
+ "F",
+ "M",
+ "A",
+ "M",
+ "J",
+ "J",
+ "A",
+ "S",
+ "O",
+ "N",
+ "D",
+ "",
+ }
+ },
{ "NumberPatterns",
new String[] {
"#,##0.###;-#,##0.###", // decimal pattern
diff --git a/src/share/classes/sun/tools/jconsole/resources/messages_ja.properties b/src/share/classes/sun/tools/jconsole/resources/messages_ja.properties
index 05f8b1b..a09ee8b 100644
--- a/src/share/classes/sun/tools/jconsole/resources/messages_ja.properties
+++ b/src/share/classes/sun/tools/jconsole/resources/messages_ja.properties
@@ -103,7 +103,7 @@
HELP_ABOUT_DIALOG_JAVA_VERSION=Java VM\u30D0\u30FC\u30B8\u30E7\u30F3:<br>{0}
HELP_ABOUT_DIALOG_MASTHEAD_ACCESSIBLE_NAME=\u30DE\u30B9\u30C8\u30D8\u30C3\u30C9\u56F3\u5F62
HELP_ABOUT_DIALOG_MASTHEAD_TITLE=JConsole\u306B\u3064\u3044\u3066
-HELP_ABOUT_DIALOG_TITLE=JConsole: \u8A73\u7D30
+HELP_ABOUT_DIALOG_TITLE=JConsole: \u60C5\u5831
HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://docs.oracle.com/javase/{0}/docs/technotes/guides/management/jconsole.html
HELP_MENU_ABOUT_TITLE=JConsole\u306B\u3064\u3044\u3066(&A)
HELP_MENU_USER_GUIDE_TITLE=\u30AA\u30F3\u30E9\u30A4\u30F3\u30FB\u30E6\u30FC\u30B6\u30FC\u30FB\u30AC\u30A4\u30C9(&U)
diff --git a/src/share/native/sun/security/ec/ECC_JNI.cpp b/src/share/native/sun/security/ec/ECC_JNI.cpp
index f2612ad..5c07645 100644
--- a/src/share/native/sun/security/ec/ECC_JNI.cpp
+++ b/src/share/native/sun/security/ec/ECC_JNI.cpp
@@ -41,7 +41,9 @@
void ThrowException(JNIEnv *env, const char *exceptionName)
{
jclass exceptionClazz = env->FindClass(exceptionName);
- env->ThrowNew(exceptionClazz, NULL);
+ if (exceptionClazz != NULL) {
+ env->ThrowNew(exceptionClazz, NULL);
+ }
}
/*
@@ -80,7 +82,6 @@
return jEncodedBytes;
}
-
/*
* Class: sun_security_ec_ECKeyPairGenerator
* Method: generateECKeyPair
@@ -103,6 +104,9 @@
params_item.len = env->GetArrayLength(encodedParams);
params_item.data =
(unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+ if (params_item.data == NULL) {
+ goto cleanup;
+ }
// Fill a new ECParams using the supplied OID
if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
@@ -170,6 +174,7 @@
SECITEM_FreeItem(&privKey->publicValue, B_FALSE);
free(privKey);
}
+
if (pSeedBuffer) {
delete [] pSeedBuffer;
}
@@ -206,6 +211,7 @@
digest_item.len = jDigestLength;
ECPrivateKey privKey;
+ privKey.privateValue.data = NULL;
// Initialize the ECParams struct
ECParams *ecparams = NULL;
@@ -213,6 +219,9 @@
params_item.len = env->GetArrayLength(encodedParams);
params_item.data =
(unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+ if (params_item.data == NULL) {
+ goto cleanup;
+ }
// Fill a new ECParams using the supplied OID
if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
@@ -226,6 +235,9 @@
privKey.privateValue.len = env->GetArrayLength(privateKey);
privKey.privateValue.data =
(unsigned char *) env->GetByteArrayElements(privateKey, 0);
+ if (privKey.privateValue.data == NULL) {
+ goto cleanup;
+ }
// Prepare a buffer for the signature (twice the key length)
pSignedDigestBuffer = new jbyte[ecparams->order.len * 2];
@@ -245,6 +257,9 @@
// Create new byte array
temp = env->NewByteArray(signature_item.len);
+ if (temp == NULL) {
+ goto cleanup;
+ }
// Copy data from native buffer
env->SetByteArrayRegion(temp, 0, signature_item.len, pSignedDigestBuffer);
@@ -317,6 +332,9 @@
params_item.len = env->GetArrayLength(encodedParams);
params_item.data =
(unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+ if (params_item.data == NULL) {
+ goto cleanup;
+ }
// Fill a new ECParams using the supplied OID
if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
@@ -369,25 +387,37 @@
(JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey, jbyteArray encodedParams)
{
jbyteArray jSecret = NULL;
+ ECParams *ecparams = NULL;
+ SECItem privateValue_item;
+ privateValue_item.data = NULL;
+ SECItem publicValue_item;
+ publicValue_item.data = NULL;
+ SECKEYECParams params_item;
+ params_item.data = NULL;
// Extract private key value
- SECItem privateValue_item;
privateValue_item.len = env->GetArrayLength(privateKey);
privateValue_item.data =
(unsigned char *) env->GetByteArrayElements(privateKey, 0);
+ if (privateValue_item.data == NULL) {
+ goto cleanup;
+ }
// Extract public key value
- SECItem publicValue_item;
publicValue_item.len = env->GetArrayLength(publicKey);
publicValue_item.data =
(unsigned char *) env->GetByteArrayElements(publicKey, 0);
+ if (publicValue_item.data == NULL) {
+ goto cleanup;
+ }
// Initialize the ECParams struct
- ECParams *ecparams = NULL;
- SECKEYECParams params_item;
params_item.len = env->GetArrayLength(encodedParams);
params_item.data =
(unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+ if (params_item.data == NULL) {
+ goto cleanup;
+ }
// Fill a new ECParams using the supplied OID
if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
@@ -409,6 +439,9 @@
// Create new byte array
jSecret = env->NewByteArray(secret_item.len);
+ if (jSecret == NULL) {
+ goto cleanup;
+ }
// Copy bytes from the SECItem buffer to a Java byte array
env->SetByteArrayRegion(jSecret, 0, secret_item.len,
diff --git a/src/solaris/classes/sun/awt/X11/XRootWindow.java b/src/solaris/classes/sun/awt/X11/XRootWindow.java
index 1a35581..6b8b162 100644
--- a/src/solaris/classes/sun/awt/X11/XRootWindow.java
+++ b/src/solaris/classes/sun/awt/X11/XRootWindow.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,8 @@
}
private XRootWindow() {
- super(new XCreateWindowParams(new Object[] {DELAYED, Boolean.TRUE}));
+ super(new XCreateWindowParams(new Object[] { DELAYED, Boolean.TRUE,
+ EVENT_MASK, XConstants.StructureNotifyMask }));
}
public void postInit(XCreateWindowParams params){
diff --git a/src/solaris/classes/sun/awt/X11/XToolkit.java b/src/solaris/classes/sun/awt/X11/XToolkit.java
index 2a628ec..800be8f 100644
--- a/src/solaris/classes/sun/awt/X11/XToolkit.java
+++ b/src/solaris/classes/sun/awt/X11/XToolkit.java
@@ -2354,9 +2354,7 @@
private static XEventDispatcher oops_waiter;
private static boolean oops_updated;
- private static boolean oops_failed;
- private XAtom oops;
- private static final long WORKAROUND_SLEEP = 100;
+ private static boolean oops_move;
/**
* @inheritDoc
@@ -2367,52 +2365,33 @@
if (oops_waiter == null) {
oops_waiter = new XEventDispatcher() {
public void dispatchEvent(XEvent e) {
- if (e.get_type() == XConstants.SelectionNotify) {
- XSelectionEvent pe = e.get_xselection();
- if (pe.get_property() == oops.getAtom()) {
- oops_updated = true;
- awtLockNotifyAll();
- } else if (pe.get_selection() == XAtom.get("WM_S0").getAtom() &&
- pe.get_target() == XAtom.get("VERSION").getAtom() &&
- pe.get_property() == 0 &&
- XlibWrapper.XGetSelectionOwner(getDisplay(), XAtom.get("WM_S0").getAtom()) == 0)
- {
- // WM forgot to acquire selection or there is no WM
- oops_failed = true;
- awtLockNotifyAll();
- }
-
+ if (e.get_type() == XConstants.ConfigureNotify) {
+ // OOPS ConfigureNotify event catched
+ oops_updated = true;
+ awtLockNotifyAll();
}
}
};
}
- if (oops == null) {
- oops = XAtom.get("OOPS");
- }
-
awtLock();
try {
addEventDispatcher(win.getWindow(), oops_waiter);
oops_updated = false;
- oops_failed = false;
- // Wait for selection notify for oops on win
long event_number = getEventNumber();
- XAtom atom = XAtom.get("WM_S0");
- if (eventLog.isLoggable(PlatformLogger.Level.FINER)) {
- eventLog.finer("WM_S0 selection owner {0}", XlibWrapper.XGetSelectionOwner(getDisplay(), atom.getAtom()));
- }
- XlibWrapper.XConvertSelection(getDisplay(), atom.getAtom(),
- XAtom.get("VERSION").getAtom(), oops.getAtom(),
- win.getWindow(), XConstants.CurrentTime);
+ // Generate OOPS ConfigureNotify event
+ XlibWrapper.XMoveWindow(getDisplay(), win.getWindow(), oops_move ? 0 : 1, 0);
+ // Change win position each time to avoid system optimization
+ oops_move = !oops_move;
XSync();
- eventLog.finer("Requested OOPS");
+ eventLog.finer("Generated OOPS ConfigureNotify event");
long start = System.currentTimeMillis();
- while (!oops_updated && !oops_failed) {
+ while (!oops_updated) {
try {
+ // Wait for OOPS ConfigureNotify event
awtLockWait(timeout);
} catch (InterruptedException e) {
throw new RuntimeException(e);
@@ -2423,20 +2402,8 @@
throw new OperationTimedOut(Long.toString(System.currentTimeMillis() - start));
}
}
- if (oops_failed && getEventNumber() - event_number == 1) {
- // If selection update failed we can simply wait some time
- // hoping some events will arrive
- awtUnlock();
- eventLog.finest("Emergency sleep");
- try {
- Thread.sleep(WORKAROUND_SLEEP);
- } catch (InterruptedException ie) {
- throw new RuntimeException(ie);
- } finally {
- awtLock();
- }
- }
- return getEventNumber() - event_number > 2;
+ // Don't take into account OOPS ConfigureNotify event
+ return getEventNumber() - event_number > 1;
} finally {
removeEventDispatcher(win.getWindow(), oops_waiter);
eventLog.finer("Exiting syncNativeQueue");
diff --git a/src/solaris/native/sun/awt/awt_util.h b/src/solaris/native/sun/awt/awt_util.h
index dd0be22..8708905 100644
--- a/src/solaris/native/sun/awt/awt_util.h
+++ b/src/solaris/native/sun/awt/awt_util.h
@@ -52,6 +52,8 @@
*/
extern XErrorHandler current_native_xerror_handler;
+Window get_xawt_root_shell(JNIEnv *env);
+
#endif /* !HEADLESS */
#ifndef INTERSECTS
diff --git a/src/solaris/native/sun/xawt/XlibWrapper.c b/src/solaris/native/sun/xawt/XlibWrapper.c
index 60298f7..f1d6318 100644
--- a/src/solaris/native/sun/xawt/XlibWrapper.c
+++ b/src/solaris/native/sun/xawt/XlibWrapper.c
@@ -2011,10 +2011,14 @@
* Toolkit thread to process PropertyNotify or SelectionNotify events.
*/
static Bool
-secondary_loop_event(Display* dpy, XEvent* event, char* arg) {
- return (event->type == SelectionNotify ||
- event->type == SelectionClear ||
- event->type == PropertyNotify) ? True : False;
+secondary_loop_event(Display* dpy, XEvent* event, XPointer xawt_root_window) {
+ return (
+ event->type == SelectionNotify ||
+ event->type == SelectionClear ||
+ event->type == PropertyNotify ||
+ (event->type == ConfigureNotify
+ && event->xany.window == *(Window*) xawt_root_window)
+ ) ? True : False;
}
@@ -2025,8 +2029,11 @@
AWT_CHECK_HAVE_LOCK_RETURN(JNI_FALSE);
exitSecondaryLoop = False;
+ Window xawt_root_window = get_xawt_root_shell(env);
+
while (!exitSecondaryLoop) {
- if (XCheckIfEvent((Display*) jlong_to_ptr(display), (XEvent*) jlong_to_ptr(ptr), secondary_loop_event, NULL)) {
+ if (XCheckIfEvent((Display*) jlong_to_ptr(display),
+ (XEvent*) jlong_to_ptr(ptr), secondary_loop_event, (XPointer) &xawt_root_window)) {
return JNI_TRUE;
}
timeout = (timeout < AWT_SECONDARY_LOOP_TIMEOUT) ? (timeout << 1) : AWT_SECONDARY_LOOP_TIMEOUT;
diff --git a/src/windows/native/sun/java2d/windows/GDIRenderer.cpp b/src/windows/native/sun/java2d/windows/GDIRenderer.cpp
index 643d64d..36991f4 100644
--- a/src/windows/native/sun/java2d/windows/GDIRenderer.cpp
+++ b/src/windows/native/sun/java2d/windows/GDIRenderer.cpp
@@ -670,7 +670,7 @@
if (ypoints != NULL) {
pPoints = TransformPoly(xpoints, ypoints, transx, transy,
tmpPts, &npoints, FALSE, FALSE);
- env->ReleasePrimitiveArrayCritical(ypointsarray, xpoints, JNI_ABORT);
+ env->ReleasePrimitiveArrayCritical(ypointsarray, ypoints, JNI_ABORT);
}
env->ReleasePrimitiveArrayCritical(xpointsarray, xpoints, JNI_ABORT);
}
diff --git a/src/windows/native/sun/security/mscapi/security.cpp b/src/windows/native/sun/security/mscapi/security.cpp
index 49cbe81..8b5d8ae 100644
--- a/src/windows/native/sun/security/mscapi/security.cpp
+++ b/src/windows/native/sun/security/mscapi/security.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -74,7 +74,10 @@
const char* pszHashAlgorithm = NULL;
ALG_ID algId = 0;
- pszHashAlgorithm = env->GetStringUTFChars(jHashAlgorithm, NULL);
+ if ((pszHashAlgorithm = env->GetStringUTFChars(jHashAlgorithm, NULL))
+ == NULL) {
+ return algId;
+ }
if ((strcmp("SHA", pszHashAlgorithm) == 0) ||
(strcmp("SHA1", pszHashAlgorithm) == 0) ||
@@ -179,7 +182,9 @@
*/
if (length < 0) {
length = env->GetArrayLength(seed);
- reseedBytes = env->GetByteArrayElements(seed, 0);
+ if ((reseedBytes = env->GetByteArrayElements(seed, 0)) == NULL) {
+ __leave;
+ }
if (::CryptGenRandom(
hCryptProv,
@@ -211,7 +216,9 @@
} else { // length == 0
length = env->GetArrayLength(seed);
- seedBytes = env->GetByteArrayElements(seed, 0);
+ if ((seedBytes = env->GetByteArrayElements(seed, 0)) == NULL) {
+ __leave;
+ }
if (::CryptGenRandom(
hCryptProv,
@@ -275,7 +282,10 @@
__try
{
// Open a system certificate store.
- pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL);
+ if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL))
+ == NULL) {
+ __leave;
+ }
if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName))
== NULL) {
@@ -710,7 +720,10 @@
__try
{
- pszKeyContainerName = env->GetStringUTFChars(keyContainerName, NULL);
+ if ((pszKeyContainerName =
+ env->GetStringUTFChars(keyContainerName, NULL)) == NULL) {
+ __leave;
+ }
// Acquire a CSP context (create a new key container).
// Prefer a PROV_RSA_AES CSP, when available, due to its support
@@ -847,7 +860,10 @@
__try
{
// Open a system certificate store.
- pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL);
+ if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL))
+ == NULL) {
+ __leave;
+ }
if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) {
ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
__leave;
@@ -1086,7 +1102,10 @@
__try
{
// Open a system certificate store.
- pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL);
+ if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL))
+ == NULL) {
+ __leave;
+ }
if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) {
ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
__leave;
@@ -1123,7 +1142,10 @@
cchNameString);
// Compare the certificate's friendly name with supplied alias name
- pszCertAliasName = env->GetStringUTFChars(jCertAliasName, NULL);
+ if ((pszCertAliasName = env->GetStringUTFChars(jCertAliasName, NULL))
+ == NULL) {
+ __leave;
+ }
if (strcmp(pszCertAliasName, pszNameString) == 0) {
// Only delete the certificate if the alias names matches
@@ -1181,7 +1203,10 @@
__try
{
- pszKeyContainerName = env->GetStringUTFChars(keyContainerName, NULL);
+ if ((pszKeyContainerName =
+ env->GetStringUTFChars(keyContainerName, NULL)) == NULL) {
+ __leave;
+ }
// Destroying the default key container is not permitted
// (because it may contain more one keypair).
@@ -1234,8 +1259,14 @@
__try
{
- pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL);
- pszCertAliasName = env->GetStringUTFChars(jCertAliasName, NULL);
+ if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL))
+ == NULL) {
+ __leave;
+ }
+ if ((pszCertAliasName = env->GetStringUTFChars(jCertAliasName, NULL))
+ == NULL) {
+ __leave;
+ }
// Open a system certificate store.
if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName)) == NULL) {
@@ -1530,7 +1561,9 @@
__try {
jsize length = env->GetArrayLength(jKeyBlob);
- keyBlob = env->GetByteArrayElements(jKeyBlob, 0);
+ if ((keyBlob = env->GetByteArrayElements(jKeyBlob, 0)) == NULL) {
+ __leave;
+ }
PUBLICKEYSTRUC* pPublicKeyStruc = (PUBLICKEYSTRUC *) keyBlob;
@@ -1580,7 +1613,9 @@
__try {
jsize length = env->GetArrayLength(jKeyBlob);
- keyBlob = env->GetByteArrayElements(jKeyBlob, 0);
+ if ((keyBlob = env->GetByteArrayElements(jKeyBlob, 0)) == NULL) {
+ __leave;
+ }
PUBLICKEYSTRUC* pPublicKeyStruc = (PUBLICKEYSTRUC *) keyBlob;
@@ -1632,6 +1667,9 @@
}
jbyte* sourceBytes = env->GetByteArrayElements(source, 0);
+ if (sourceBytes == NULL) {
+ return -1;
+ }
// Copy bytes from the end of the source array to the beginning of the
// destination array (until the destination array is full).
@@ -1740,45 +1778,61 @@
}
// The length argument must be the smaller of jPublicExponentLength
// and sizeof(pRsaPubKey->pubkey)
- convertToLittleEndian(env, jPublicExponent,
- (jbyte *) &(pRsaPubKey->pubexp), jPublicExponentLength);
+ if ((jElementLength = convertToLittleEndian(env, jPublicExponent,
+ (jbyte *) &(pRsaPubKey->pubexp), jPublicExponentLength)) < 0) {
+ __leave;
+ }
// Modulus n
jBlobElement =
(jbyte *) (jBlobBytes + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY));
- jElementLength = convertToLittleEndian(env, jModulus, jBlobElement,
- jKeyByteLength);
+ if ((jElementLength = convertToLittleEndian(env, jModulus, jBlobElement,
+ jKeyByteLength)) < 0) {
+ __leave;
+ }
if (bGeneratePrivateKeyBlob) {
// Prime p
jBlobElement += jElementLength;
- jElementLength = convertToLittleEndian(env, jPrimeP, jBlobElement,
- jKeyByteLength / 2);
+ if ((jElementLength = convertToLittleEndian(env, jPrimeP,
+ jBlobElement, jKeyByteLength / 2)) < 0) {
+ __leave;
+ }
// Prime q
jBlobElement += jElementLength;
- jElementLength = convertToLittleEndian(env, jPrimeQ, jBlobElement,
- jKeyByteLength / 2);
+ if ((jElementLength = convertToLittleEndian(env, jPrimeQ,
+ jBlobElement, jKeyByteLength / 2)) < 0) {
+ __leave;
+ }
// Prime exponent p
jBlobElement += jElementLength;
- jElementLength = convertToLittleEndian(env, jExponentP,
- jBlobElement, jKeyByteLength / 2);
+ if ((jElementLength = convertToLittleEndian(env, jExponentP,
+ jBlobElement, jKeyByteLength / 2)) < 0) {
+ __leave;
+ }
// Prime exponent q
jBlobElement += jElementLength;
- jElementLength = convertToLittleEndian(env, jExponentQ,
- jBlobElement, jKeyByteLength / 2);
+ if ((jElementLength = convertToLittleEndian(env, jExponentQ,
+ jBlobElement, jKeyByteLength / 2)) < 0) {
+ __leave;
+ }
// CRT coefficient
jBlobElement += jElementLength;
- jElementLength = convertToLittleEndian(env, jCrtCoefficient,
- jBlobElement, jKeyByteLength / 2);
+ if ((jElementLength = convertToLittleEndian(env, jCrtCoefficient,
+ jBlobElement, jKeyByteLength / 2)) < 0) {
+ __leave;
+ }
// Private exponent
jBlobElement += jElementLength;
- convertToLittleEndian(env, jPrivateExponent, jBlobElement,
- jKeyByteLength);
+ if ((jElementLength = convertToLittleEndian(env, jPrivateExponent,
+ jBlobElement, jKeyByteLength)) < 0) {
+ __leave;
+ }
}
jBlob = env->NewByteArray(jBlobLength);
@@ -1849,9 +1903,15 @@
__try
{
- pszKeyContainerName = env->GetStringUTFChars(keyContainerName, NULL);
+ if ((pszKeyContainerName =
+ env->GetStringUTFChars(keyContainerName, NULL)) == NULL) {
+ __leave;
+ }
dwBlobLen = env->GetArrayLength(keyBlob);
- pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0);
+ if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0))
+ == NULL) {
+ __leave;
+ }
// Acquire a CSP context (create a new key container).
if (::CryptAcquireContext(
@@ -1923,7 +1983,10 @@
__try
{
dwBlobLen = env->GetArrayLength(keyBlob);
- pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0);
+ if ((pbKeyBlob = (BYTE *) env->GetByteArrayElements(keyBlob, 0))
+ == NULL) {
+ __leave;
+ }
// Acquire a CSP context (create a new key container).
// Prefer a PROV_RSA_AES CSP, when available, due to its support
diff --git a/src/windows/native/sun/windows/awt_Component.cpp b/src/windows/native/sun/windows/awt_Component.cpp
index 5bd7bf4..3baae0f 100644
--- a/src/windows/native/sun/windows/awt_Component.cpp
+++ b/src/windows/native/sun/windows/awt_Component.cpp
@@ -3955,7 +3955,6 @@
DASSERT(stringCls);
CHECK_NULL(stringCls);
clauseReading = env->NewObjectArray(cClause, stringCls, NULL);
- env->DeleteLocalRef(stringCls);
DASSERT(clauseReading);
CHECK_NULL(clauseReading);
for (int i=0; i<cClause; i++) env->SetObjectArrayElement(clauseReading, i, rgClauseReading[i]);
diff --git a/src/windows/native/sun/windows/awt_TextArea.cpp b/src/windows/native/sun/windows/awt_TextArea.cpp
index 938da4c..427a0b8 100644
--- a/src/windows/native/sun/windows/awt_TextArea.cpp
+++ b/src/windows/native/sun/windows/awt_TextArea.cpp
@@ -47,16 +47,12 @@
jfieldID AwtTextArea::scrollbarVisibilityID;
-WNDPROC AwtTextArea::sm_pDefWindowProc = NULL;
-
/************************************************************************
* AwtTextArea methods
*/
AwtTextArea::AwtTextArea() {
- m_bIgnoreEnChange = FALSE;
m_bCanUndo = FALSE;
- m_hEditCtrl = NULL;
m_lHDeltaAccum = 0;
m_lVDeltaAccum = 0;
}
@@ -67,10 +63,6 @@
void AwtTextArea::Dispose()
{
- if (m_hEditCtrl != NULL) {
- VERIFY(::DestroyWindow(m_hEditCtrl));
- m_hEditCtrl = NULL;
- }
AwtTextComponent::Dispose();
}
@@ -91,10 +83,6 @@
}
}
-void AwtTextArea::EditGetSel(CHARRANGE &cr) {
- SendMessage(EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&cr));
-}
-
/* Count how many '\n's are there in jStr */
size_t AwtTextArea::CountNewLines(JNIEnv *env, jstring jStr, size_t maxlen)
{
@@ -149,159 +137,6 @@
return retValue;
}
-/*
- * This routine is a window procedure for the subclass of the standard edit control
- * used to generate context menu. RichEdit controls don't have built-in context menu.
- * To implement this functionality we have to create an invisible edit control and
- * forward WM_CONTEXTMENU messages from a RichEdit control to this helper edit control.
- * While the edit control context menu is active we intercept the message generated in
- * response to particular item selection and forward it back to the RichEdit control.
- * (See AwtTextArea::WmContextMenu for more details).
- */
-LRESULT
-AwtTextArea::EditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
-
- static BOOL bContextMenuActive = FALSE;
-
- LRESULT retValue = 0;
- MsgRouting mr = mrDoDefault;
-
- DASSERT(::IsWindow(::GetParent(hWnd)));
-
- switch (message) {
- case WM_UNDO:
- case WM_CUT:
- case WM_COPY:
- case WM_PASTE:
- case WM_CLEAR:
- case EM_SETSEL:
- if (bContextMenuActive) {
- ::SendMessage(::GetParent(hWnd), message, wParam, lParam);
- mr = mrConsume;
- }
- break;
- case WM_CONTEXTMENU:
- bContextMenuActive = TRUE;
- break;
- }
-
- if (mr == mrDoDefault) {
- DASSERT(sm_pDefWindowProc != NULL);
- retValue = ::CallWindowProc(sm_pDefWindowProc,
- hWnd, message, wParam, lParam);
- }
-
- if (message == WM_CONTEXTMENU) {
- bContextMenuActive = FALSE;
- }
-
- return retValue;
-}
-
-MsgRouting
-AwtTextArea::WmContextMenu(HWND hCtrl, UINT xPos, UINT yPos) {
- /* Use the system provided edit control class to generate context menu. */
- if (m_hEditCtrl == NULL) {
- DWORD dwStyle = WS_CHILD;
- DWORD dwExStyle = 0;
- m_hEditCtrl = ::CreateWindowEx(dwExStyle,
- L"EDIT",
- L"TEXT",
- dwStyle,
- 0, 0, 0, 0,
- GetHWnd(),
- reinterpret_cast<HMENU>(
- static_cast<INT_PTR>(
- CreateControlID())),
- AwtToolkit::GetInstance().GetModuleHandle(),
- NULL);
- DASSERT(m_hEditCtrl != NULL);
- if (sm_pDefWindowProc == NULL) {
- sm_pDefWindowProc = (WNDPROC)::GetWindowLongPtr(m_hEditCtrl,
- GWLP_WNDPROC);
- }
- ::SetLastError(0);
- INT_PTR ret = ::SetWindowLongPtr(m_hEditCtrl, GWLP_WNDPROC,
- (INT_PTR)AwtTextArea::EditProc);
- DASSERT(ret != 0 || ::GetLastError() == 0);
- }
-
- /*
- * Tricks on the edit control to ensure that its context menu has
- * the correct set of enabled items according to the RichEdit state.
- */
- ::SetWindowText(m_hEditCtrl, TEXT("TEXT"));
-
- if (m_bCanUndo == TRUE && SendMessage(EM_CANUNDO)) {
- /* Enable 'Undo' item. */
- ::SendMessage(m_hEditCtrl, WM_CHAR, 'A', 0);
- }
-
- {
- /*
- * Initial selection for the edit control - (0,1).
- * This enables 'Cut', 'Copy' and 'Delete' and 'Select All'.
- */
- INT nStart = 0;
- INT nEnd = 1;
- if (SendMessage(EM_SELECTIONTYPE) == SEL_EMPTY) {
- /*
- * RichEdit selection is empty - clear selection of the edit control.
- * This disables 'Cut', 'Copy' and 'Delete'.
- */
- nStart = -1;
- nEnd = 0;
- } else {
-
- CHARRANGE cr;
- EditGetSel(cr);
- /* Check if all the text is selected. */
- if (cr.cpMin == 0) {
-
- int len = ::GetWindowTextLength(GetHWnd());
- if (cr.cpMin == 0 && cr.cpMax >= len) {
- /*
- * All the text is selected in RichEdit - select all the
- * text in the edit control. This disables 'Select All'.
- */
- nStart = 0;
- nEnd = -1;
- }
- }
- }
- ::SendMessage(m_hEditCtrl, EM_SETSEL, (WPARAM)nStart, (LPARAM)nEnd);
- }
-
- /* Disable 'Paste' item if the RichEdit control is read-only. */
- ::SendMessage(m_hEditCtrl, EM_SETREADONLY,
- GetStyle() & ES_READONLY ? TRUE : FALSE, 0);
-
- POINT p;
- p.x = xPos;
- p.y = yPos;
-
- /*
- * If the context menu is requested with SHIFT+F10 or VK_APPS key,
- * we position its top left corner to the center of the RichEdit
- * client rect.
- */
- if (p.x == -1 && p.y == -1) {
- RECT r;
- VERIFY(::GetClientRect(GetHWnd(), &r));
- p.x = (r.left + r.right) / 2;
- p.y = (r.top + r.bottom) / 2;
- VERIFY(::ClientToScreen(GetHWnd(), &p));
- }
-
- // The context menu steals focus from the proxy.
- // So, set the focus-restore flag up.
- SetRestoreFocus(TRUE);
- ::SendMessage(m_hEditCtrl, WM_CONTEXTMENU, (WPARAM)m_hEditCtrl, MAKELPARAM(p.x, p.y));
- SetRestoreFocus(FALSE);
-
- return mrConsume;
-}
-
MsgRouting
AwtTextArea::WmNcHitTest(UINT x, UINT y, LRESULT& retVal)
{
@@ -314,27 +149,8 @@
MsgRouting
-AwtTextArea::WmNotify(UINT notifyCode)
-{
- if (notifyCode == EN_CHANGE) {
- /*
- * Ignore notifications if the text hasn't been changed.
- * EN_CHANGE sent on character formatting changes as well.
- */
- if (m_bIgnoreEnChange == FALSE) {
- m_bCanUndo = TRUE;
- DoCallback("valueChanged", "()V");
- } else {
- m_bCanUndo = FALSE;
- }
- }
- return mrDoDefault;
-}
-
-MsgRouting
AwtTextArea::HandleEvent(MSG *msg, BOOL synthetic)
{
- MsgRouting returnVal;
/*
* RichEdit 1.0 control starts internal message loop if the
* left mouse button is pressed while the cursor is not over
@@ -486,26 +302,6 @@
}
delete msg;
return mrConsume;
- } else if (msg->message == WM_RBUTTONUP ||
- (msg->message == WM_SYSKEYDOWN && msg->wParam == VK_F10 &&
- HIBYTE(::GetKeyState(VK_SHIFT)))) {
- POINT p;
- if (msg->message == WM_RBUTTONUP) {
- VERIFY(::GetCursorPos(&p));
- } else {
- p.x = -1;
- p.y = -1;
- }
-
- if (!::PostMessage(GetHWnd(), WM_CONTEXTMENU, (WPARAM)GetHWnd(),
- MAKELPARAM(p.x, p.y))) {
- JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
- JNU_ThrowInternalError(env, "Message not posted, native event queue may be full.");
- env->ExceptionDescribe();
- env->ExceptionClear();
- }
- delete msg;
- return mrConsume;
} else if (msg->message == WM_MOUSEWHEEL) {
// 4417236: If there is an old version of RichEd32.dll which
// does not provide the mouse wheel scrolling we have to
@@ -596,15 +392,7 @@
// 4417236: end of fix
}
- /*
- * Store the 'synthetic' parameter so that the WM_PASTE security check
- * happens only for synthetic events.
- */
- m_synthetic = synthetic;
- returnVal = AwtComponent::HandleEvent(msg, synthetic);
- m_synthetic = FALSE;
-
- return returnVal;
+ return AwtTextComponent::HandleEvent(msg, synthetic);
}
diff --git a/src/windows/native/sun/windows/awt_TextArea.h b/src/windows/native/sun/windows/awt_TextArea.h
index 931a319..1738e64 100644
--- a/src/windows/native/sun/windows/awt_TextArea.h
+++ b/src/windows/native/sun/windows/awt_TextArea.h
@@ -57,17 +57,11 @@
static size_t GetALength(JNIEnv* env, jstring jStr, size_t maxlen);
LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
- static LRESULT CALLBACK EditProc(HWND hWnd, UINT message,
- WPARAM wParam, LPARAM lParam);
MsgRouting WmEnable(BOOL fEnabled);
- MsgRouting WmContextMenu(HWND hCtrl, UINT xPos, UINT yPos);
- MsgRouting WmNotify(UINT notifyCode);
MsgRouting WmNcHitTest(UINT x, UINT y, LRESULT &retVal);
MsgRouting HandleEvent(MSG *msg, BOOL synthetic);
- INLINE void SetIgnoreEnChange(BOOL b) { m_bIgnoreEnChange = b; }
-
virtual BOOL InheritsNativeMouseWheelBehavior();
virtual void Reshape(int x, int y, int w, int h);
@@ -81,22 +75,7 @@
protected:
void EditSetSel(CHARRANGE &cr);
- void EditGetSel(CHARRANGE &cr);
private:
- // RichEdit 1.0 control generates EN_CHANGE notifications not only
- // on text changes, but also on any character formatting change.
- // This flag is true when the latter case is detected.
- BOOL m_bIgnoreEnChange;
-
- // RichEdit 1.0 control undoes a character formatting change
- // if it is the latest. We don't create our own undo buffer,
- // but just prohibit undo in case if the latest operation
- // is a formatting change.
- BOOL m_bCanUndo;
-
- HWND m_hEditCtrl;
- static WNDPROC sm_pDefWindowProc;
-
LONG m_lHDeltaAccum;
LONG m_lVDeltaAccum;
diff --git a/src/windows/native/sun/windows/awt_TextComponent.cpp b/src/windows/native/sun/windows/awt_TextComponent.cpp
index d96a194..eaa8bca 100644
--- a/src/windows/native/sun/windows/awt_TextComponent.cpp
+++ b/src/windows/native/sun/windows/awt_TextComponent.cpp
@@ -66,6 +66,8 @@
m_lLastPos = -1;
m_isLFonly = FALSE;
m_EOLchecked = FALSE;
+ m_hEditCtrl = NULL;
+ m_bIgnoreEnChange = FALSE;
// javaEventsMask = 0; // accessibility support
}
@@ -213,6 +215,16 @@
return c;
}
+void AwtTextComponent::Dispose()
+{
+ if (m_hEditCtrl != NULL) {
+ VERIFY(::DestroyWindow(m_hEditCtrl));
+ m_hEditCtrl = NULL;
+ }
+ AwtComponent::Dispose();
+}
+
+
LRESULT
AwtTextComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
@@ -322,7 +334,16 @@
AwtTextComponent::WmNotify(UINT notifyCode)
{
if (notifyCode == EN_CHANGE) {
- DoCallback("valueChanged", "()V");
+ /*
+ * Ignore notifications if the text hasn't been changed.
+ * EN_CHANGE sent on character formatting changes as well.
+ */
+ if (m_bIgnoreEnChange == FALSE) {
+ m_bCanUndo = TRUE;
+ DoCallback("valueChanged", "()V");
+ } else {
+ m_bCanUndo = FALSE;
+ }
}
return mrDoDefault;
}
@@ -337,6 +358,28 @@
{
MsgRouting returnVal;
+ if (msg->message == WM_RBUTTONUP ||
+ (msg->message == WM_SYSKEYDOWN && msg->wParam == VK_F10 &&
+ HIBYTE(::GetKeyState(VK_SHIFT)))) {
+ POINT p;
+ if (msg->message == WM_RBUTTONUP) {
+ VERIFY(::GetCursorPos(&p));
+ } else {
+ p.x = -1;
+ p.y = -1;
+ }
+
+ if (!::PostMessage(GetHWnd(), WM_CONTEXTMENU, (WPARAM)GetHWnd(),
+ MAKELPARAM(p.x, p.y))) {
+ JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
+ JNU_ThrowInternalError(env, "Message not posted, native event queue may be full.");
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ }
+ delete msg;
+ return mrConsume;
+ }
+
/*
* Store the 'synthetic' parameter so that the WM_PASTE security check
* happens only for synthetic events.
@@ -701,6 +744,10 @@
SendMessage(EM_SETBKGNDCOLOR, (WPARAM)FALSE, (LPARAM)GetBackgroundColor());
}
+void AwtTextComponent::EditGetSel(CHARRANGE &cr) {
+ SendMessage(EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&cr));
+}
+
/************************************************************************
* WTextComponentPeer native methods
@@ -983,6 +1030,161 @@
}
+/*
+ * This routine is a window procedure for the subclass of the standard edit control
+ * used to generate context menu. RichEdit controls don't have built-in context menu.
+ * To implement this functionality we have to create an invisible edit control and
+ * forward WM_CONTEXTMENU messages from a RichEdit control to this helper edit control.
+ * While the edit control context menu is active we intercept the message generated in
+ * response to particular item selection and forward it back to the RichEdit control.
+ * (See AwtTextArea::WmContextMenu for more details).
+ */
+
+WNDPROC AwtTextComponent::sm_pDefWindowProc = NULL;
+
+LRESULT
+AwtTextComponent::EditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
+
+ static BOOL bContextMenuActive = FALSE;
+
+ LRESULT retValue = 0;
+ MsgRouting mr = mrDoDefault;
+
+ DASSERT(::IsWindow(::GetParent(hWnd)));
+
+ switch (message) {
+ case WM_UNDO:
+ case WM_CUT:
+ case WM_COPY:
+ case WM_PASTE:
+ case WM_CLEAR:
+ case EM_SETSEL:
+ if (bContextMenuActive) {
+ ::SendMessage(::GetParent(hWnd), message, wParam, lParam);
+ mr = mrConsume;
+ }
+ break;
+ case WM_CONTEXTMENU:
+ bContextMenuActive = TRUE;
+ break;
+ }
+
+ if (mr == mrDoDefault) {
+ DASSERT(sm_pDefWindowProc != NULL);
+ retValue = ::CallWindowProc(sm_pDefWindowProc,
+ hWnd, message, wParam, lParam);
+ }
+
+ if (message == WM_CONTEXTMENU) {
+ bContextMenuActive = FALSE;
+ }
+
+ return retValue;
+}
+
+MsgRouting
+AwtTextComponent::WmContextMenu(HWND hCtrl, UINT xPos, UINT yPos) {
+ /* Use the system provided edit control class to generate context menu. */
+ if (m_hEditCtrl == NULL) {
+ DWORD dwStyle = WS_CHILD;
+ DWORD dwExStyle = 0;
+ m_hEditCtrl = ::CreateWindowEx(dwExStyle,
+ L"EDIT",
+ L"TEXT",
+ dwStyle,
+ 0, 0, 0, 0,
+ GetHWnd(),
+ reinterpret_cast<HMENU>(
+ static_cast<INT_PTR>(
+ CreateControlID())),
+ AwtToolkit::GetInstance().GetModuleHandle(),
+ NULL);
+ DASSERT(m_hEditCtrl != NULL);
+ if (sm_pDefWindowProc == NULL) {
+ sm_pDefWindowProc = (WNDPROC)::GetWindowLongPtr(m_hEditCtrl,
+ GWLP_WNDPROC);
+ }
+ ::SetLastError(0);
+ INT_PTR ret = ::SetWindowLongPtr(m_hEditCtrl, GWLP_WNDPROC,
+ (INT_PTR)AwtTextArea::EditProc);
+ DASSERT(ret != 0 || ::GetLastError() == 0);
+ }
+
+ /*
+ * Tricks on the edit control to ensure that its context menu has
+ * the correct set of enabled items according to the RichEdit state.
+ */
+ ::SetWindowText(m_hEditCtrl, TEXT("TEXT"));
+
+ if (m_bCanUndo == TRUE && SendMessage(EM_CANUNDO)) {
+ /* Enable 'Undo' item. */
+ ::SendMessage(m_hEditCtrl, WM_CHAR, 'A', 0);
+ }
+
+ {
+ /*
+ * Initial selection for the edit control - (0,1).
+ * This enables 'Cut', 'Copy' and 'Delete' and 'Select All'.
+ */
+ INT nStart = 0;
+ INT nEnd = 1;
+ if (SendMessage(EM_SELECTIONTYPE) == SEL_EMPTY) {
+ /*
+ * RichEdit selection is empty - clear selection of the edit control.
+ * This disables 'Cut', 'Copy' and 'Delete'.
+ */
+ nStart = -1;
+ nEnd = 0;
+ } else {
+
+ CHARRANGE cr;
+ EditGetSel(cr);
+ /* Check if all the text is selected. */
+ if (cr.cpMin == 0) {
+
+ int len = ::GetWindowTextLength(GetHWnd());
+ if (cr.cpMin == 0 && cr.cpMax >= len) {
+ /*
+ * All the text is selected in RichEdit - select all the
+ * text in the edit control. This disables 'Select All'.
+ */
+ nStart = 0;
+ nEnd = -1;
+ }
+ }
+ }
+ ::SendMessage(m_hEditCtrl, EM_SETSEL, (WPARAM)nStart, (LPARAM)nEnd);
+ }
+
+ /* Disable 'Paste' item if the RichEdit control is read-only. */
+ ::SendMessage(m_hEditCtrl, EM_SETREADONLY,
+ GetStyle() & ES_READONLY ? TRUE : FALSE, 0);
+
+ POINT p;
+ p.x = xPos;
+ p.y = yPos;
+
+ /*
+ * If the context menu is requested with SHIFT+F10 or VK_APPS key,
+ * we position its top left corner to the center of the RichEdit
+ * client rect.
+ */
+ if (p.x == -1 && p.y == -1) {
+ RECT r;
+ VERIFY(::GetClientRect(GetHWnd(), &r));
+ p.x = (r.left + r.right) / 2;
+ p.y = (r.top + r.bottom) / 2;
+ VERIFY(::ClientToScreen(GetHWnd(), &p));
+ }
+
+ // The context menu steals focus from the proxy.
+ // So, set the focus-restore flag up.
+ SetRestoreFocus(TRUE);
+ ::SendMessage(m_hEditCtrl, WM_CONTEXTMENU, (WPARAM)m_hEditCtrl, MAKELPARAM(p.x, p.y));
+ SetRestoreFocus(FALSE);
+
+ return mrConsume;
+}
//
// Accessibility support
diff --git a/src/windows/native/sun/windows/awt_TextComponent.h b/src/windows/native/sun/windows/awt_TextComponent.h
index 356ed64..2a9eecc 100644
--- a/src/windows/native/sun/windows/awt_TextComponent.h
+++ b/src/windows/native/sun/windows/awt_TextComponent.h
@@ -47,6 +47,8 @@
static AwtTextComponent* Create(jobject self, jobject parent, BOOL isMultiline);
+ virtual void Dispose();
+
virtual LPCTSTR GetClassName();
LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
@@ -83,6 +85,8 @@
MsgRouting HandleEvent(MSG *msg, BOOL synthetic);
MsgRouting WmPaste();
+ INLINE void SetIgnoreEnChange(BOOL b) { m_bIgnoreEnChange = b; }
+
virtual BOOL IsFocusingMouseMessage(MSG *pMsg);
/* To be fully implemented in a future release
@@ -115,11 +119,24 @@
INLINE VOID SetEndSelectionPos(LONG lPos) { m_lEndPos = lPos; }
INLINE VOID SetLastSelectionPos(LONG lPos) { m_lLastPos = lPos; }
+ void EditGetSel(CHARRANGE &cr);
+
// Used to prevent untrusted code from synthesizing a WM_PASTE message
// by posting a <CTRL>-V KeyEvent
BOOL m_synthetic;
LONG EditGetCharFromPos(POINT& pt);
+ // RichEdit 1.0 control generates EN_CHANGE notifications not only
+ // on text changes, but also on any character formatting change.
+ // This flag is true when the latter case is detected.
+ BOOL m_bIgnoreEnChange;
+
+ // RichEdit 1.0 control undoes a character formatting change
+ // if it is the latest. We don't create our own undo buffer,
+ // but just prohibit undo in case if the latest operation
+ // is a formatting change.
+ BOOL m_bCanUndo;
+
/*****************************************************************
* Inner class OleCallback declaration.
*/
@@ -166,6 +183,13 @@
static OleCallback sm_oleCallback;
+ static WNDPROC sm_pDefWindowProc;
+ HWND m_hEditCtrl;
+
+ static LRESULT CALLBACK EditProc(HWND hWnd, UINT message,
+ WPARAM wParam, LPARAM lParam);
+ MsgRouting WmContextMenu(HWND hCtrl, UINT xPos, UINT yPos);
+
//
// Accessibility support
//
diff --git a/src/windows/native/sun/windows/awt_TextField.cpp b/src/windows/native/sun/windows/awt_TextField.cpp
index b37b5c7..1c966aa 100644
--- a/src/windows/native/sun/windows/awt_TextField.cpp
+++ b/src/windows/native/sun/windows/awt_TextField.cpp
@@ -249,13 +249,7 @@
}
}
- /*
- * Store the 'synthetic' parameter so that the WM_PASTE security check
- * happens only for synthetic events.
- */
- m_synthetic = synthetic;
- returnVal = AwtComponent::HandleEvent(msg, synthetic);
- m_synthetic = FALSE;
+ returnVal = AwtTextComponent::HandleEvent(msg, synthetic);
if(systemBeeperEnabled){
SystemParametersInfo(SPI_SETBEEP, 1, NULL, 0);
diff --git a/test/com/sun/jdi/EvalInterfaceStatic.sh b/test/com/sun/jdi/EvalInterfaceStatic.sh
new file mode 100644
index 0000000..92340b3
--- /dev/null
+++ b/test/com/sun/jdi/EvalInterfaceStatic.sh
@@ -0,0 +1,126 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 8031195
+# @summary JDB allows evaluation of calls to static interface methods
+# @author Jaroslav Bachorik
+#
+# @run shell/timeout=300 EvalInterfaceStatic.sh
+
+# The test exercises the ability to invoke static methods on interfaces.
+# Static interface methods are a new feature added in JDK8.
+#
+# The test makes sure that it is, at all, possible to invoke an interface
+# static method and that the static methods are not inherited by extending
+# interfaces.
+
+classname=EvalStaticInterfaces
+
+createJavaFile()
+{
+ cat <<EOF > $classname.java.1
+public interface $classname {
+ static String staticMethod1() {
+ return "base:staticMethod1";
+ }
+
+ static String staticMethod2() {
+ return "base:staticMethod2";
+ }
+
+ public static void main(String[] args) {
+ // prove that these work
+ System.out.println("base staticMethod1(): " + $classname.staticMethod1());
+ System.out.println("base staticMethod2(): " + $classname.staticMethod2());
+ System.out.println("overridden staticMethod2(): " + Extended$classname.staticMethod2());
+ System.out.println("base staticMethod3(): " + Extended$classname.staticMethod3());
+
+ gus();
+ }
+
+ static void gus() {
+ int x = 0; // @1 breakpoint
+ }
+}
+
+interface Extended$classname extends $classname {
+ static String staticMethod2() {
+ return "extended:staticMethod2";
+ }
+
+ static String staticMethod3() {
+ return "extended:staticMethod3";
+ }
+}
+
+
+
+EOF
+}
+
+# drive jdb by sending cmds to it and examining its output
+dojdbCmds()
+{
+ setBkpts @1
+ runToBkpt @1
+
+ cmd eval "$classname.staticMethod1()"
+ jdbFailIfNotPresent "base:staticMethod1" 2
+
+ cmd eval "$classname.staticMethod2()"
+ jdbFailIfNotPresent "base:staticMethod2" 2
+
+ cmd eval "Extended$classname.staticMethod1()"
+ jdbFailIfPresent "base:staticMethod1" 2
+
+ cmd eval "Extended$classname.staticMethod2()"
+ jdbFailIfNotPresent "extended:staticMethod2" 2
+
+ cmd eval "Extended$classname.staticMethod3()"
+ jdbFailIfNotPresent "extended:staticMethod3" 2
+}
+
+
+mysetup()
+{
+ if [ -z "$TESTSRC" ] ; then
+ TESTSRC=.
+ fi
+
+ for ii in . $TESTSRC $TESTSRC/.. ; do
+ if [ -r "$ii/ShellScaffold.sh" ] ; then
+ . $ii/ShellScaffold.sh
+ break
+ fi
+ done
+}
+
+# You could replace this next line with the contents
+# of ShellScaffold.sh and this script will run just the same.
+mysetup
+
+runit
+pass
diff --git a/test/com/sun/jdi/InterfaceMethodsTest.java b/test/com/sun/jdi/InterfaceMethodsTest.java
new file mode 100644
index 0000000..e127fa5
--- /dev/null
+++ b/test/com/sun/jdi/InterfaceMethodsTest.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8031195
+ * @summary JDI: Add support for static and default methods in interfaces
+ *
+ * @run build TestScaffold VMConnection TargetListener TargetAdapter
+ * @run build InterfaceMethodsTest
+ * @run main InterfaceMethodsTest
+ */
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import java.util.Collections;
+
+public class InterfaceMethodsTest extends TestScaffold {
+ private static final int RESULT_A = 1;
+ private static final int RESULT_B = 1;
+ private static final int RESULT_TARGET = 1;
+ static interface InterfaceA {
+ static int staticMethodA() {
+ System.out.println("-InterfaceA: static interface method A-");
+ return RESULT_A;
+ }
+ static int staticMethodB() {
+ System.out.println("-InterfaceA: static interface method B-");
+ return RESULT_A;
+ }
+ default int defaultMethodA() {
+ System.out.println("-InterfaceA: default interface method A-");
+ return RESULT_A;
+ }
+ default int defaultMethodB() {
+ System.out.println("-InterfaceA: default interface method B-");
+ return RESULT_A;
+ }
+ default int defaultMethodC() {
+ System.out.println("-InterfaceA: default interface method C-");
+ return RESULT_A;
+ }
+
+ int implementedMethod();
+ }
+
+ static interface InterfaceB extends InterfaceA {
+ @Override
+ default int defaultMethodC() {
+ System.out.println("-InterfaceB: overridden default interface method C-");
+ return RESULT_B;
+ }
+ default int defaultMethodD() {
+ System.out.println("-InterfaceB: default interface method D-");
+ return RESULT_B;
+ }
+
+ static int staticMethodB() {
+ System.out.println("-InterfaceB: overridden static interface method B-");
+ return RESULT_B;
+ }
+
+ static int staticMethodC() {
+ System.out.println("-InterfaceB: static interface method C-");
+ return RESULT_B;
+ }
+ }
+
+ final static class TargetClass implements InterfaceB {
+ public int classMethod() {
+ System.out.println("-TargetClass: class only method-");
+ return RESULT_TARGET;
+ }
+
+ @Override
+ public int implementedMethod() {
+ System.out.println("-TargetClass: implemented non-default interface method-");
+ return RESULT_TARGET;
+ }
+
+ @Override
+ public int defaultMethodB() {
+ System.out.println("-TargetClass: overridden default interface method D");
+
+ return RESULT_TARGET;
+ }
+
+ public static void main(String[] args) {
+ TargetClass tc = new TargetClass();
+ tc.doTests(tc);
+ }
+
+ private void doTests(TargetClass ref) {
+ // break
+ }
+ }
+
+ public InterfaceMethodsTest(String[] args) {
+ super(args);
+ }
+
+ public static void main(String[] args) throws Exception {
+ new InterfaceMethodsTest(args).startTests();
+ }
+
+ private static final String TEST_CLASS_NAME = InterfaceMethodsTest.class.getName().replace('.', '/');
+ private static final String TARGET_CLASS_NAME = TargetClass.class.getName().replace('.', '/');
+ private static final String INTERFACEA_NAME = InterfaceA.class.getName().replace('.', '/');
+ private static final String INTERFACEB_NAME = InterfaceB.class.getName().replace('.', '/');
+
+ protected void runTests() throws Exception {
+ /*
+ * Get to the top of main()
+ * to determine targetClass and mainThread
+ */
+ BreakpointEvent bpe = startToMain(TARGET_CLASS_NAME);
+
+ bpe = resumeTo(TARGET_CLASS_NAME, "doTests", "(L" + TARGET_CLASS_NAME +";)V");
+
+ mainThread = bpe.thread();
+
+ StackFrame frame = mainThread.frame(0);
+ ObjectReference thisObject = frame.thisObject();
+ ObjectReference ref = (ObjectReference)frame.getArgumentValues().get(0);
+
+ ReferenceType targetClass = bpe.location().declaringType();
+ testImplementationClass(targetClass, thisObject);
+
+ testInterfaceA(ref);
+
+ testInterfaceB(ref);
+
+ /*
+ * resume the target listening for events
+ */
+ listenUntilVMDisconnect();
+
+ /*
+ * deal with results of test
+ * if anything has called failure("foo") testFailed will be true
+ */
+ if (!testFailed) {
+ println("InterfaceMethodsTest: passed");
+ } else {
+ throw new Exception("InterfaceMethodsTest: failed");
+ }
+ }
+
+ private void testInterfaceA(ObjectReference ref) {
+ // Test non-virtual calls on InterfaceA
+
+ ReferenceType ifaceClass = (ReferenceType)vm().classesByName(INTERFACEA_NAME).get(0);
+ /* Default method calls */
+
+ // invoke the InterfaceA's "defaultMethodA"
+ testInvokePos(ifaceClass, ref, "defaultMethodA", "()I", vm().mirrorOf(RESULT_A));
+
+ // invoke the InterfaceA's "defaultMethodB"
+ testInvokePos(ifaceClass, ref, "defaultMethodB", "()I", vm().mirrorOf(RESULT_A));
+
+ // invoke the InterfaceA's "defaultMethodC"
+ testInvokePos(ifaceClass, ref, "defaultMethodC", "()I", vm().mirrorOf(RESULT_A));
+
+ // "defaultMethodD" from InterfaceB is not accessible from here
+ testInvokeNeg(ifaceClass, ref, "defaultMethodD", "()I", vm().mirrorOf(RESULT_B),
+ "Attempted to invoke non-existing method");
+
+ // trying to invoke the asbtract method "implementedMethod"
+ testInvokeNeg(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(TARGET_CLASS_NAME),
+ "Invocation of non-default methods is not supported");
+
+
+ /* Static method calls */
+
+ // invoke interface static method A
+ testInvokePos(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A));
+
+ // try to invoke static method A on the instance
+ testInvokePos(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A));
+
+ // invoke interface static method B
+ testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_A));
+
+ // try to invoke static method B on the instance
+ testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_A));
+ }
+
+ private void testInterfaceB(ObjectReference ref) {
+ // Test non-virtual calls on InterfaceB
+ ReferenceType ifaceClass = (ReferenceType)vm().classesByName(INTERFACEB_NAME).get(0);
+
+ /* Default method calls */
+
+ // invoke the inherited "defaultMethodA"
+ testInvokePos(ifaceClass, ref, "defaultMethodA", "()I", vm().mirrorOf(RESULT_A));
+
+ // invoke the inherited "defaultMethodB"
+ testInvokePos(ifaceClass, ref, "defaultMethodB", "()I", vm().mirrorOf(RESULT_A));
+
+ // invoke the inherited and overridden "defaultMethodC"
+ testInvokePos(ifaceClass, ref, "defaultMethodC", "()I", vm().mirrorOf(RESULT_B));
+
+ // invoke InterfaceB only "defaultMethodD"
+ testInvokePos(ifaceClass, ref, "defaultMethodD", "()I", vm().mirrorOf(RESULT_B));
+
+ // "implementedMethod" is not present in InterfaceB
+ testInvokeNeg(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(RESULT_TARGET),
+ "Invocation of non-default methods is not supported");
+
+
+ /* Static method calls*/
+
+ // "staticMethodA" must not be inherited by InterfaceB
+ testInvokeNeg(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
+ "Static interface methods are not inheritable");
+
+ // however it is possible to call "staticMethodA" on the actual instance
+ testInvokeNeg(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
+ "Static interface methods are not inheritable");
+
+ // "staticMethodB" is overridden in InterfaceB
+ testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_B));
+
+ // the instance invokes the overriden form of "staticMethodB" from InterfaceB
+ testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_B));
+
+ // "staticMethodC" is present only in InterfaceB
+ testInvokePos(ifaceClass, null, "staticMethodC", "()I", vm().mirrorOf(RESULT_B));
+
+ // "staticMethodC" should be reachable from the instance too
+ testInvokePos(ifaceClass, ref, "staticMethodC", "()I", vm().mirrorOf(RESULT_B));
+ }
+
+ private void testImplementationClass(ReferenceType targetClass, ObjectReference thisObject) {
+ // Test invocations on the implementation object
+
+ /* Default method calls */
+
+ // "defaultMethodA" is accessible and not overridden
+ testInvokePos(targetClass, thisObject, "defaultMethodA", "()I", vm().mirrorOf(RESULT_TARGET));
+
+ // "defaultMethodB" is accessible and overridden in TargetClass
+ testInvokePos(targetClass, thisObject, "defaultMethodB", "()I", vm().mirrorOf(RESULT_TARGET));
+
+ // "defaultMethodC" is accessible and overridden in InterfaceB
+ testInvokePos(targetClass, thisObject, "defaultMethodC", "()I", vm().mirrorOf(RESULT_TARGET));
+
+ // "defaultMethodD" is accessible
+ testInvokePos(targetClass, thisObject, "defaultMethodD", "()I", vm().mirrorOf(RESULT_TARGET));
+
+
+ /* Non-default instance method calls */
+
+ // "classMethod" declared in TargetClass is accessible
+ testInvokePos(targetClass, thisObject, "classMethod", "()I", vm().mirrorOf(RESULT_TARGET));
+
+ // the abstract "implementedMethod" has been implemented in TargetClass
+ testInvokePos(targetClass, thisObject, "implementedMethod", "()I", vm().mirrorOf(RESULT_TARGET));
+
+
+ /* Static method calls */
+
+ // All the static methods declared by the interfaces are not reachable from the instance of the implementor class
+ testInvokeNeg(targetClass, thisObject, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
+ "Static interface methods are not inheritable");
+
+ testInvokeNeg(targetClass, thisObject, "staticMethodB", "()I", vm().mirrorOf(RESULT_B),
+ "Static interface methods are not inheritable");
+
+ testInvokeNeg(targetClass, thisObject, "staticMethodC", "()I", vm().mirrorOf(RESULT_B),
+ "Static interface methods are not inheritable");
+
+ // All the static methods declared by the interfaces are not reachable through the implementor class
+ testInvokeNeg(targetClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
+ "Static interface methods are not inheritable");
+
+ testInvokeNeg(targetClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_B),
+ "Static interface methods are not inheritable");
+
+ testInvokeNeg(targetClass, null, "staticMethodC", "()I", vm().mirrorOf(RESULT_B),
+ "Static interface methods are not inheritable");
+ }
+
+ private void testInvokePos(ReferenceType targetClass, ObjectReference ref, String methodName,
+ String methodSig, Value value) {
+ logInvocation(ref, methodName, methodSig, targetClass);
+ try {
+ invoke(targetClass, ref, methodName, methodSig, value);
+ System.err.println("--- PASSED");
+ } catch (Exception e) {
+ System.err.println("--- FAILED");
+ failure("FAILED: Invocation failed with error message " + e.getLocalizedMessage());
+ }
+ }
+
+ private void testInvokeNeg(ReferenceType targetClass, ObjectReference ref, String methodName,
+ String methodSig, Value value, String msg) {
+ logInvocation(ref, methodName, methodSig, targetClass);
+ try {
+ invoke(targetClass, ref, methodName, methodSig, value);
+ System.err.println("--- FAILED");
+ failure("FAILED: " + msg);
+ } catch (Exception e) {
+ System.err.println("--- PASSED");
+
+ }
+ }
+
+ private void invoke(ReferenceType targetClass, ObjectReference ref, String methodName,
+ String methodSig, Value value)
+ throws Exception {
+ Method method = getMethod(targetClass, methodName, methodSig);
+ if (method == null) {
+ throw new Exception("Can't find method: " + methodName + " for class = " + targetClass);
+ }
+
+ println("Invoking " + (method.isAbstract() ? "abstract " : " ") + "method: " + method);
+
+ Value returnValue = null;
+ if (ref != null) {
+ returnValue = invokeInstance(ref, method);
+ } else {
+ returnValue = invokeStatic(targetClass, method);
+ }
+
+ println(" return val = " + returnValue);
+ // It has to be the same value as what we passed in!
+ if (returnValue.equals(value)) {
+ println(" " + method.name() + " return value matches: "
+ + value);
+ } else {
+ if (value != null) {
+ throw new Exception(method.name() + " returned: " + returnValue +
+ " expected: " + value );
+ } else {
+ println(" " + method.name() + " return value : " + returnValue);
+ }
+
+ }
+ }
+
+ private Value invokeInstance(ObjectReference ref, Method method) throws Exception {
+ return ref.invokeMethod(mainThread, method, Collections.emptyList(), ObjectReference.INVOKE_NONVIRTUAL);
+ }
+
+ private Value invokeStatic(ReferenceType refType, Method method) throws Exception {
+ if (refType instanceof ClassType) {
+ return ((ClassType)refType).invokeMethod(mainThread, method, Collections.emptyList(), ObjectReference.INVOKE_NONVIRTUAL);
+ } else {
+ return ((InterfaceType)refType).invokeMethod(mainThread, method, Collections.emptyList(), ObjectReference.INVOKE_NONVIRTUAL);
+ }
+ }
+
+ private Method getMethod(ReferenceType rt, String name, String signature) {
+ if (rt == null) return null;
+ Method m = findMethod(rt, name, signature);
+ if (m == null) {
+ if (rt instanceof ClassType) {
+ for (Object ifc : ((ClassType)rt).interfaces()) {
+ m = getMethod((ReferenceType)ifc, name, signature);
+ if (m != null) {
+ break;
+ }
+ }
+ if (m == null) {
+ m = getMethod(((ClassType)rt).superclass(), name, signature);
+ } else {
+ if (m.isStatic()) {
+ // interface static methods are not inherited
+ m = null;
+ }
+ }
+ } else if (rt instanceof InterfaceType) {
+ for(Object ifc : ((InterfaceType)rt).superinterfaces()) {
+ m = getMethod((ReferenceType)ifc, name, signature);
+ if (m != null) {
+ if (m.isStatic()) {
+ // interface static methods are not inherited
+ m = null;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return m;
+ }
+
+ private void logInvocation(ObjectReference ref, String methodName, String methodSig, ReferenceType targetClass) {
+ if (ref != null) {
+ System.err.println("Invoking: " + ref.referenceType().name() + "." +
+ methodName + methodSig + " with target of type " +
+ targetClass.name());
+ } else {
+ System.err.println("Invoking static : " + targetClass.name() + "." +
+ methodName + methodSig);
+ }
+ }
+}
+
+
+
diff --git a/test/com/sun/jdi/VisibleMethods.java b/test/com/sun/jdi/VisibleMethods.java
new file mode 100644
index 0000000..70f7f5a
--- /dev/null
+++ b/test/com/sun/jdi/VisibleMethods.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2013, 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
+ * @summary Test ReferenceType.visibleMethods
+ * @bug 8028430
+ *
+ * @author Staffan Larsen
+ *
+ * @run build TestScaffold VMConnection TargetListener TargetAdapter
+ * @run compile -g VisibleMethods.java
+ * @run main VisibleMethods
+ */
+import com.sun.jdi.Method;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.StackFrame;
+import com.sun.jdi.StringReference;
+import com.sun.jdi.ThreadReference;
+import com.sun.jdi.event.BreakpointEvent;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/********** target program **********/
+
+interface Super {
+ public void m(Object o); // This method should not be visible in AC
+ public void m(String s); // This method should not be visible in AC
+}
+
+interface One extends Super {
+ public void m(Object o);
+ public void m1(); // Either this method or Two.m1 should be visible in AC
+}
+
+interface Two extends Super {
+ public void m(String s);
+ public void m1(); // Either this method or One.m1 should be visible in AC
+}
+
+abstract class AC implements One, Two {
+}
+
+class CC extends AC {
+ public void m(Object o) {
+ }
+ public void m(String s) {
+ }
+ public void m1() {
+ }
+ public static void main(String[] args) {
+ System.out.println("Goodbye from VisibleMethods!");
+ }
+}
+
+/********** test program **********/
+
+public class VisibleMethods extends TestScaffold {
+ ReferenceType targetClass;
+ ThreadReference mainThread;
+
+ VisibleMethods(String args[]) {
+ super(args);
+ }
+
+ public static void main(String[] args) throws Exception {
+ new VisibleMethods(args).startTests();
+ }
+
+ /********** test core **********/
+
+ protected void runTests()
+ throws Exception
+ {
+ /*
+ * Run to String.<init>
+ */
+ startToMain("CC");
+
+ ReferenceType ac = findReferenceType("AC");
+ List<String> visible = ac.visibleMethods().
+ stream().
+ map(Method::toString).
+ collect(Collectors.toList());
+
+ System.out.println("visibleMethods(): " + visible);
+
+ verifyContains(visible, 1, "Two.m(java.lang.String)");
+ verifyContains(visible, 1, "One.m(java.lang.Object)");
+ verifyContains(visible, 0, "Super.m(java.lang.Object)");
+ verifyContains(visible, 0, "Super.m(java.lang.String)");
+ verifyContains(visible, 1, "Two.m1()", "One.m1()");
+
+ /*
+ * resume the target listening for events
+ */
+ listenUntilVMDisconnect();
+ }
+
+ private void verifyContains(List<String> methods, int matches,
+ String... sigs) throws Exception {
+ if (countMatches(methods, sigs) != matches) {
+ throw new Exception("visibleMethods() should have contained "
+ + matches + " entry/entries from " + Arrays.toString(sigs));
+ }
+ }
+
+ private int countMatches(List<String> list1, String[] list2) {
+ int count = 0;
+ for (String s1 : list1) {
+ for (String s2 : list2) {
+ if (s1.equals(s2)) {
+ count++;
+ }
+ }
+ }
+ return count;
+ }
+}
diff --git a/test/java/awt/Focus/SortingFPT/JDK8048887.java b/test/java/awt/Focus/SortingFPT/JDK8048887.java
index 72f0ada..0128706 100644
--- a/test/java/awt/Focus/SortingFPT/JDK8048887.java
+++ b/test/java/awt/Focus/SortingFPT/JDK8048887.java
@@ -26,7 +26,7 @@
@bug 8048887
@summary Tests SortingFTP for an exception caused by the tim-sort algo.
@author anton.tarasov: area=awt.focus
- @run main JDK8040632
+ @run main JDK8048887
*/
import javax.swing.JFrame;
diff --git a/test/java/net/InetAddress/IPv4Formats.java b/test/java/net/InetAddress/IPv4Formats.java
index 7c6dc86..e626043 100644
--- a/test/java/net/InetAddress/IPv4Formats.java
+++ b/test/java/net/InetAddress/IPv4Formats.java
@@ -27,6 +27,7 @@
* @summary InetAddress.getByName behaves differently on windows
*/
import java.net.*;
+import java.util.UUID;
public class IPv4Formats {
public static void main(String[] args) {
@@ -36,7 +37,7 @@
{"126.1", "126.0.0.1"},
{"128.50.65534", "128.50.255.254"},
{"192.168.1.2", "192.168.1.2"},
- {"hello.foo.bar", null},
+ {"invalidhost.invalid", null},
{"1024.1.2.3", null},
{"128.14.66000", null }
};
diff --git a/test/java/util/logging/FileHandlerPath.java b/test/java/util/logging/FileHandlerPath.java
new file mode 100644
index 0000000..9385909
--- /dev/null
+++ b/test/java/util/logging/FileHandlerPath.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import static java.nio.file.StandardOpenOption.CREATE_NEW;
+import static java.nio.file.StandardOpenOption.WRITE;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Properties;
+import java.util.PropertyPermission;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.FileHandler;
+import java.util.logging.LogManager;
+import java.util.logging.LoggingPermission;
+
+/**
+ * @test
+ * @bug 8059269
+ * @summary tests that using a simple (non composite) pattern does not lead
+ * to NPE when the lock file already exists.
+ * @run main/othervm FileHandlerPath UNSECURE
+ * @run main/othervm FileHandlerPath SECURE
+ * @author danielfuchs
+ */
+public class FileHandlerPath {
+
+ /**
+ * We will test the simple pattern in two configurations.
+ * UNSECURE: No security manager.
+ * SECURE: With the security manager present - and the required
+ * permissions granted.
+ */
+ public static enum TestCase {
+ UNSECURE, SECURE;
+ public void run(Properties propertyFile) throws Exception {
+ System.out.println("Running test case: " + name());
+ Configure.setUp(this, propertyFile);
+ test(this.name() + " " + propertyFile.getProperty("test.name"), propertyFile);
+ }
+ }
+
+
+ // Use a random name provided by UUID to avoid collision with other tests
+ final static String logFile = FileHandlerPath.class.getSimpleName() + "_"
+ + UUID.randomUUID().toString() + ".log";
+ final static String tmpLogFile;
+ final static String userDir = System.getProperty("user.dir");
+ final static String tmpDir = System.getProperty("java.io.tmpdir");
+ private static final List<Properties> properties;
+ static {
+ tmpLogFile = new File(tmpDir, logFile).toString();
+ Properties props1 = new Properties();
+ Properties props2 = new Properties();
+ props1.setProperty("test.name", "relative file");
+ props1.setProperty("test.file.name", logFile);
+ props1.setProperty(FileHandler.class.getName() + ".pattern", logFile);
+ props1.setProperty(FileHandler.class.getName() + ".count", "1");
+ props2.setProperty("test.name", "absoluste file");
+ props2.setProperty("test.file.name", tmpLogFile);
+ props2.setProperty(FileHandler.class.getName() + ".pattern", "%t/" + logFile);
+ props2.setProperty(FileHandler.class.getName() + ".count", "1");
+ properties = Collections.unmodifiableList(Arrays.asList(
+ props1,
+ props2));
+ }
+
+ public static void main(String... args) throws Exception {
+
+ if (args == null || args.length == 0) {
+ args = new String[] {
+ TestCase.UNSECURE.name(),
+ TestCase.SECURE.name(),
+ };
+ }
+
+ // Sanity checks
+
+ if (!Files.isWritable(Paths.get(userDir))) {
+ throw new RuntimeException(userDir +
+ ": user.dir is not writable - can't run test.");
+ }
+ if (!Files.isWritable(Paths.get(tmpDir))) {
+ throw new RuntimeException(tmpDir +
+ ": java.io.tmpdir is not writable - can't run test.");
+ }
+
+ File[] files = {
+ new File(logFile),
+ new File(tmpLogFile),
+ new File(logFile+".1"),
+ new File(tmpLogFile+".1"),
+ new File(logFile+".lck"),
+ new File(tmpLogFile+".lck"),
+ new File(logFile+".1.lck"),
+ new File(tmpLogFile+".1.lck")
+ };
+
+ for (File log : files) {
+ if (log.exists()) {
+ throw new Exception(log +": file already exists - can't run test.");
+ }
+ }
+
+ // Now start the real test
+
+ try {
+ for (String testName : args) {
+ for (Properties propertyFile : properties) {
+ TestCase test = TestCase.valueOf(testName);
+ test.run(propertyFile);
+ }
+ }
+ } finally {
+ // Cleanup...
+ Configure.doPrivileged(() -> {
+ for(File log : files) {
+ try {
+ final boolean isLockFile = log.getName().endsWith(".lck");
+ // lock file should already be deleted, except if the
+ // test failed in exception.
+ // log file should all be present, except if the test
+ // failed in exception.
+ if (log.exists()) {
+ if (!isLockFile) {
+ System.out.println("deleting "+log.toString());
+ } else {
+ System.err.println("deleting lock file "+log.toString());
+ }
+ log.delete();
+ } else {
+ if (!isLockFile) {
+ System.err.println(log.toString() + ": not found.");
+ }
+ }
+ } catch (Throwable t) {
+ // should not happen
+ t.printStackTrace();
+ }
+ }
+ });
+ }
+ }
+
+ static class Configure {
+ static Policy policy = null;
+ static final AtomicBoolean allowAll = new AtomicBoolean(false);
+ static void setUp(TestCase test, Properties propertyFile) {
+ switch (test) {
+ case SECURE:
+ if (policy == null && System.getSecurityManager() != null) {
+ throw new IllegalStateException("SecurityManager already set");
+ } else if (policy == null) {
+ policy = new SimplePolicy(TestCase.SECURE, allowAll);
+ Policy.setPolicy(policy);
+ System.setSecurityManager(new SecurityManager());
+ }
+ if (System.getSecurityManager() == null) {
+ throw new IllegalStateException("No SecurityManager.");
+ }
+ if (policy == null) {
+ throw new IllegalStateException("policy not configured");
+ }
+ break;
+ case UNSECURE:
+ if (System.getSecurityManager() != null) {
+ throw new IllegalStateException("SecurityManager already set");
+ }
+ break;
+ default:
+ new InternalError("No such testcase: " + test);
+ }
+ doPrivileged(() -> {
+ try {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ propertyFile.store(bytes, propertyFile.getProperty("test.name"));
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes.toByteArray());
+ LogManager.getLogManager().readConfiguration(bais);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ });
+ }
+ static void doPrivileged(Runnable run) {
+ allowAll.set(true);
+ try {
+ run.run();
+ } finally {
+ allowAll.set(false);
+ }
+ }
+ }
+
+ public static void test(String name, Properties props) throws Exception {
+ System.out.println("Testing: " + name);
+ String file = props.getProperty("test.file.name");
+ // create the lock files first - in order to take the path that
+ // used to trigger the NPE
+ Files.createFile(Paths.get(file + ".lck"));
+ Files.createFile(Paths.get(file + ".1.lck"));
+ final FileHandler f1 = new FileHandler();
+ final FileHandler f2 = new FileHandler();
+ f1.close();
+ f2.close();
+ System.out.println("Success for " + name);
+ }
+
+
+ final static class PermissionsBuilder {
+ final Permissions perms;
+ public PermissionsBuilder() {
+ this(new Permissions());
+ }
+ public PermissionsBuilder(Permissions perms) {
+ this.perms = perms;
+ }
+ public PermissionsBuilder add(Permission p) {
+ perms.add(p);
+ return this;
+ }
+ public PermissionsBuilder addAll(PermissionCollection col) {
+ if (col != null) {
+ for (Enumeration<Permission> e = col.elements(); e.hasMoreElements(); ) {
+ perms.add(e.nextElement());
+ }
+ }
+ return this;
+ }
+ public Permissions toPermissions() {
+ final PermissionsBuilder builder = new PermissionsBuilder();
+ builder.addAll(perms);
+ return builder.perms;
+ }
+ }
+
+ public static class SimplePolicy extends Policy {
+
+ final Permissions permissions;
+ final Permissions allPermissions;
+ final AtomicBoolean allowAll;
+ public SimplePolicy(TestCase test, AtomicBoolean allowAll) {
+ this.allowAll = allowAll;
+ permissions = new Permissions();
+ permissions.add(new LoggingPermission("control", null)); // needed by new FileHandler()
+ permissions.add(new FilePermission("<<ALL FILES>>", "read")); // needed by new FileHandler()
+ permissions.add(new FilePermission(logFile, "write,delete")); // needed by new FileHandler()
+ permissions.add(new FilePermission(logFile+".lck", "write,delete")); // needed by FileHandler.close()
+ permissions.add(new FilePermission(logFile+".1", "write,delete")); // needed by new FileHandler()
+ permissions.add(new FilePermission(logFile+".1.lck", "write,delete")); // needed by FileHandler.close()
+ permissions.add(new FilePermission(tmpLogFile, "write,delete")); // needed by new FileHandler()
+ permissions.add(new FilePermission(tmpLogFile+".lck", "write,delete")); // needed by FileHandler.close()
+ permissions.add(new FilePermission(tmpLogFile+".1", "write,delete")); // needed by new FileHandler()
+ permissions.add(new FilePermission(tmpLogFile+".1.lck", "write,delete")); // needed by FileHandler.close()
+ permissions.add(new FilePermission(userDir, "write")); // needed by new FileHandler()
+ permissions.add(new FilePermission(tmpDir, "write")); // needed by new FileHandler()
+ permissions.add(new PropertyPermission("user.dir", "read"));
+ permissions.add(new PropertyPermission("java.io.tmpdir", "read"));
+ allPermissions = new Permissions();
+ allPermissions.add(new java.security.AllPermission());
+ }
+
+ @Override
+ public boolean implies(ProtectionDomain domain, Permission permission) {
+ if (allowAll.get()) return allPermissions.implies(permission);
+ return permissions.implies(permission);
+ }
+
+ @Override
+ public PermissionCollection getPermissions(CodeSource codesource) {
+ return new PermissionsBuilder().addAll(allowAll.get()
+ ? allPermissions : permissions).toPermissions();
+ }
+
+ @Override
+ public PermissionCollection getPermissions(ProtectionDomain domain) {
+ return new PermissionsBuilder().addAll(allowAll.get()
+ ? allPermissions : permissions).toPermissions();
+ }
+ }
+
+}
diff --git a/test/javax/xml/ws/xsanymixed/CopyingResponse.java b/test/javax/xml/ws/xsanymixed/CopyingResponse.java
new file mode 100644
index 0000000..88c4084
--- /dev/null
+++ b/test/javax/xml/ws/xsanymixed/CopyingResponse.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+import org.somewhere.ws.EchoRequest;
+import org.somewhere.ws.EchoResponse;
+
+public class CopyingResponse extends EchoResponse {
+
+ public CopyingResponse() {}
+
+ public CopyingResponse(EchoRequest request) {
+ content = request.getContent();
+ }
+}
diff --git a/test/javax/xml/ws/xsanymixed/ServiceImpl.java b/test/javax/xml/ws/xsanymixed/ServiceImpl.java
new file mode 100644
index 0000000..b045893
--- /dev/null
+++ b/test/javax/xml/ws/xsanymixed/ServiceImpl.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.somewhere.ws.EchoRequest;
+import org.somewhere.ws.EchoResponse;
+import org.somewhere.ws.TestPort;
+
+import javax.jws.WebService;
+import javax.xml.namespace.QName;
+
+
+/**
+ * Simple Webservice implementation just copying xml part as is
+ * from incoming request into outgoing response
+ */
+@WebService(
+ endpointInterface = "org.somewhere.ws.TestPort",
+ targetNamespace = "http://ws.somewhere.org/",
+ serviceName = "TestService",
+ portName = "TestPort")
+public class ServiceImpl implements TestPort {
+
+ public static final QName PORT_NAME = new QName("http://ws.somewhere.org/", "TestPort");
+ public static final QName SERVICE_NAME = new QName("http://ws.somewhere.org/", "TestService");
+
+ @Override
+ public EchoResponse echo(EchoRequest request) {
+ return new CopyingResponse(request);
+ }
+
+}
diff --git a/test/javax/xml/ws/xsanymixed/Test.java b/test/javax/xml/ws/xsanymixed/Test.java
new file mode 100644
index 0000000..4287d8c
--- /dev/null
+++ b/test/javax/xml/ws/xsanymixed/Test.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8036981 8038966 8051441
+ * @summary the content of xs:any content:mixed should remain as is,
+ * no white space changes and no changes to namespace prefixes
+ * @run shell compile-wsdl.sh
+ * @run main/othervm Test
+ */
+
+import com.sun.net.httpserver.HttpServer;
+
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.ws.Dispatch;
+import javax.xml.ws.Endpoint;
+import javax.xml.ws.Service;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.InetSocketAddress;
+import java.net.URL;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+public class Test {
+
+ private static HttpServer httpServer;
+ private static Endpoint endpoint;
+ private static final String NL = System.getProperty("line.separator");
+
+ private static final String XS_ANY_MIXED_PART =
+ "<AppHdr xmlns=\"urn:head.001\">" + NL +
+ " <Fr>" + NL + NL +
+ "<FIId xmlns=\"urn:head.009\">" + NL + NL +
+ " any" + NL +
+ " white" + NL +
+ " space" + NL + NL +
+ " <FinInstnId>... and" + NL + NL +
+ " NO namespace prefixes!!!" + NL + NL +
+ " </FinInstnId>" + NL + NL +
+ " </FIId>" + NL +
+ "</Fr>" + NL +
+ "</AppHdr>";
+
+ private static final String XML_REQUEST = "<soap:Envelope " +
+ "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
+ "xmlns:ws=\"http://ws.somewhere.org/\">" +
+ "<soap:Header/><soap:Body>" +
+ "<ws:echoRequest>" + NL +
+ XS_ANY_MIXED_PART + NL +
+ "</ws:echoRequest>" +
+ "</soap:Body></soap:Envelope>";
+
+ private static String deployWebservice() throws IOException {
+ // Manually create HttpServer here using ephemeral address for port
+ // so as to not end up with attempt to bind to an in-use port
+ httpServer = HttpServer.create(new InetSocketAddress(0), 0);
+ httpServer.start();
+ endpoint = Endpoint.create(new ServiceImpl());
+ endpoint.publish(httpServer.createContext("/wservice"));
+
+ String wsdlAddress = "http://localhost:" + httpServer.getAddress().getPort() + "/wservice?wsdl";
+ log("address = " + wsdlAddress);
+ return wsdlAddress;
+ }
+
+ private static void stopWebservice() {
+ if (endpoint != null && endpoint.isPublished()) {
+ endpoint.stop();
+ }
+ if (httpServer != null) {
+ httpServer.stop(0);
+ }
+ }
+
+ public static void main(String[] args) throws IOException, TransformerException {
+
+ try {
+ String address = deployWebservice();
+ Service service = Service.create(new URL(address), ServiceImpl.SERVICE_NAME);
+
+ Dispatch<Source> d = service.createDispatch(ServiceImpl.PORT_NAME, Source.class, Service.Mode.MESSAGE);
+ Source response = d.invoke(new StreamSource(new StringReader(XML_REQUEST)));
+
+ String resultXml = toString(response);
+
+ log("= request ======== \n");
+ log(XML_REQUEST);
+ log("= result ========= \n");
+ log(resultXml);
+ log("\n==================");
+
+ boolean xsAnyMixedPartSame = resultXml.contains(XS_ANY_MIXED_PART);
+ log("resultXml.contains(XS_ANY_PART) = " + xsAnyMixedPartSame);
+ if (!xsAnyMixedPartSame) {
+ fail("The xs:any content=mixed part is supposed to be same in request and response.");
+ throw new RuntimeException();
+ }
+
+ log("TEST PASSED");
+ } finally {
+ stopWebservice();
+
+ // if you need to debug or explore wsdl generation result
+ // comment this line out:
+ deleteGeneratedFiles();
+ }
+ }
+
+ private static String toString(Source response) throws TransformerException, IOException {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ transformer.transform(response, new StreamResult(bos));
+ bos.close();
+ return new String(bos.toByteArray());
+ }
+
+ private static void fail(String message) {
+ log("TEST FAILED.");
+ throw new RuntimeException(message);
+ }
+
+ private static void log(String msg) {
+ System.out.println(msg);
+ }
+
+ private static void deleteGeneratedFiles() {
+ Path p = Paths.get("..", "classes", "javax", "xml", "ws", "xsanymixed", "org");
+ System.out.println("performing cleanup, deleting wsdl compilation result: " + p.toFile().getAbsolutePath());
+ if (Files.exists(p)) {
+ try {
+ Files.walkFileTree(p, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(
+ Path file,
+ BasicFileAttributes attrs) throws IOException {
+
+ System.out.println("deleting file [" + file.toFile().getAbsoluteFile() + "]");
+ Files.delete(file);
+ return CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(
+ Path dir,
+ IOException exc) throws IOException {
+
+ System.out.println("deleting dir [" + dir.toFile().getAbsoluteFile() + "]");
+ if (exc == null) {
+ Files.delete(dir);
+ return CONTINUE;
+ } else {
+ throw exc;
+ }
+ }
+ });
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+ }
+
+}
diff --git a/test/javax/xml/ws/xsanymixed/compile-wsdl.sh b/test/javax/xml/ws/xsanymixed/compile-wsdl.sh
new file mode 100644
index 0000000..a93050a
--- /dev/null
+++ b/test/javax/xml/ws/xsanymixed/compile-wsdl.sh
@@ -0,0 +1,36 @@
+#! /bin/sh
+
+#
+# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+#
+
+if [ "x$TESTJAVA" = x ]; then
+ TESTJAVA=$1; shift
+ TESTCLASSES=.
+fi
+
+echo "compiling [test-service.wsdl] wsdl ..."
+$TESTJAVA/bin/wsimport -keep -d ${TESTCLASSES} ${TESTSRC}/service.wsdl
+
+echo "WSDL compiled. Main test class Test.java can be compiled now."
diff --git a/test/javax/xml/ws/xsanymixed/service.wsdl b/test/javax/xml/ws/xsanymixed/service.wsdl
new file mode 100644
index 0000000..3a8f541
--- /dev/null
+++ b/test/javax/xml/ws/xsanymixed/service.wsdl
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+ Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ This code is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 only, as
+ published by the Free Software Foundation.
+
+ This code is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ version 2 for more details (a copy is included in the LICENSE file that
+ accompanied this code).
+
+ You should have received a copy of the GNU General Public License version
+ 2 along with this work; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ or visit www.oracle.com if you need additional information or have any
+ questions.
+-->
+<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
+ xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
+ xmlns:tns="http://ws.somewhere.org/"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
+ name="TestService"
+ targetNamespace="http://ws.somewhere.org/">
+
+ <types>
+ <xsd:schema targetNamespace="http://ws.somewhere.org/" version="1.0"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://ws.somewhere.org/">
+
+ <xsd:element type="tns:echoRequest" name="echoRequest"/>
+ <xsd:element type="tns:echoResponse" name="echoResponse"/>
+
+ <xsd:complexType name="echoRequest" mixed="true">
+ <xsd:sequence>
+ <xsd:any namespace="##any" processContents="skip" minOccurs="1" maxOccurs="10"/>
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="echoResponse" mixed="true">
+ <xsd:sequence>
+ <xsd:any namespace="##any" processContents="skip" minOccurs="1" maxOccurs="10"/>
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:schema>
+ </types>
+
+ <message name="echoRequest">
+ <part element="tns:echoRequest" name="parameters"/>
+ </message>
+ <message name="echoResponse">
+ <part element="tns:echoResponse" name="parameters"/>
+ </message>
+
+ <portType name="TestPort">
+ <operation name="echo">
+ <input message="tns:echoRequest" wsam:Action="http://ws.somewhere.org/tester/echoRequest"/>
+ <output message="tns:echoResponse" wsam:Action="http://ws.somewhere.org/tester/echoResponse"/>
+ </operation>
+ </portType>
+
+ <binding name="TestServicePortBinding" type="tns:TestPort">
+ <soap:binding style="document"
+ transport="http://schemas.xmlsoap.org/soap/http"/>
+
+ <operation name="echo">
+ <soap:operation soapAction=""/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ </operation>
+ </binding>
+
+ <service name="TestService">
+ <port binding="tns:TestServicePortBinding" name="TestPort">
+ <soap:address location="http://localhost/ws/tester"/>
+ </port>
+ </service>
+</definitions>
diff --git a/test/sun/awt/datatransfer/DataFlavorComparatorTest1.java b/test/sun/awt/datatransfer/DataFlavorComparatorTest1.java
new file mode 100644
index 0000000..cc926c8
--- /dev/null
+++ b/test/sun/awt/datatransfer/DataFlavorComparatorTest1.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ @bug 8058473
+ @summary "Comparison method violates its general contract" when using Clipboard
+ Ensure that DataTransferer.DataFlavorComparator conforms to Comparator contract
+ @author Anton Nashatyrev
+ @run main DataFlavorComparatorTest1
+*/
+import sun.awt.datatransfer.DataTransferer;
+
+import java.awt.datatransfer.DataFlavor;
+import java.util.Comparator;
+
+public class DataFlavorComparatorTest1 {
+
+ public static void main(String[] args) throws Exception {
+ String[] mimes = new String[] {
+ "text/plain",
+ "text/plain; charset=unicode",
+ "text/plain; charset=cp1251",
+ "text/plain; charset=unicode; class=java.io.InputStream",
+ "text/plain; charset=unicode; class=java.io.Serializable",
+ "text/plain; charset=unicode; class=java.lang.Object",
+ "text/plain; class=java.lang.String",
+ "text/plain; class=java.io.Reader",
+ "text/plain; class=java.lang.Object",
+ "text/html",
+ "text/html; charset=unicode",
+ "text/html; charset=cp1251",
+ "text/html; charset=unicode; class=java.io.InputStream",
+ "text/html; charset=unicode; class=java.io.Serializable",
+ "text/html; charset=unicode; class=java.lang.Object",
+ "text/html; class=java.lang.String",
+ "text/html; class=java.io.Reader",
+ "text/html; class=java.lang.Object",
+ "text/unknown",
+ "text/unknown; charset=unicode",
+ "text/unknown; charset=cp1251",
+ "text/unknown; charset=unicode; class=java.io.InputStream",
+ "text/unknown; charset=unicode; class=java.io.Serializable",
+ "text/unknown; charset=unicode; class=java.lang.Object",
+ "text/unknown; class=java.lang.String",
+ "text/unknown; class=java.io.Reader",
+ "text/unknown; class=java.lang.Object",
+ "application/unknown; class=java.io.InputStream",
+ "application/unknown; class=java.lang.Object",
+ "application/unknown",
+ "application/x-java-jvm-local-objectref; class=java.io.InputStream",
+ "application/x-java-jvm-local-objectref; class=java.lang.Object",
+ "application/x-java-jvm-local-objectref",
+ "unknown/flavor",
+ "unknown/flavor; class=java.io.InputStream",
+ "unknown/flavor; class=java.lang.Object",
+ };
+
+ DataFlavor[] flavors = new DataFlavor[mimes.length];
+ for (int i = 0; i < flavors.length; i++) {
+ flavors[i] = new DataFlavor(mimes[i]);
+ }
+
+ testComparator(new DataTransferer.DataFlavorComparator(true), flavors);
+ testComparator(new DataTransferer.DataFlavorComparator(false), flavors);
+
+ }
+
+ private static void testComparator(Comparator cmp, DataFlavor[] flavs)
+ throws ClassNotFoundException {
+
+ for (DataFlavor x: flavs) {
+ for (DataFlavor y: flavs) {
+ if (Math.signum(cmp.compare(x,y)) != -Math.signum(cmp.compare(y,x))) {
+ throw new RuntimeException("Antisymmetry violated: " + x + ", " + y);
+ }
+ if (cmp.compare(x,y) == 0 && !x.equals(y)) {
+ throw new RuntimeException("Equals rule violated: " + x + ", " + y);
+ }
+ for (DataFlavor z: flavs) {
+ if (cmp.compare(x,y) == 0) {
+ if (Math.signum(cmp.compare(x, z)) != Math.signum(cmp.compare(y, z))) {
+ throw new RuntimeException("Transitivity (1) violated: " + x + ", " + y + ", " + z);
+ }
+ } else {
+ if (Math.signum(cmp.compare(x, y)) == Math.signum(cmp.compare(y, z))) {
+ if (Math.signum(cmp.compare(x, y)) != Math.signum(cmp.compare(x, z))) {
+ throw new RuntimeException("Transitivity (2) violated: " + x + ", " + y + ", " + z);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/test/sun/security/jgss/spnego/NotPreferredMech.java b/test/sun/security/jgss/spnego/NotPreferredMech.java
new file mode 100644
index 0000000..5eb8150
--- /dev/null
+++ b/test/sun/security/jgss/spnego/NotPreferredMech.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8048194
+ * @run main/othervm NotPreferredMech
+ * @summary GSSContext.acceptSecContext fails when a supported mech is not initiator preferred
+ */
+
+import org.ietf.jgss.*;
+import sun.security.jgss.*;
+import sun.security.jgss.spnego.NegTokenInit;
+import sun.security.jgss.spnego.NegTokenTarg;
+import sun.security.util.BitArray;
+import sun.security.util.DerOutputStream;
+import sun.security.util.DerValue;
+import sun.security.util.ObjectIdentifier;
+
+import java.io.ByteArrayOutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+public class NotPreferredMech {
+
+ public static void main(String[] argv) throws Exception {
+
+ // Generates a NegTokenInit mechTypes field, with an
+ // unsupported mech as the preferred.
+ DerOutputStream mech = new DerOutputStream();
+ mech.write(new Oid("1.2.3.4").getDER());
+ mech.write(GSSUtil.GSS_KRB5_MECH_OID.getDER());
+ DerOutputStream mechTypeList = new DerOutputStream();
+ mechTypeList.write(DerValue.tag_Sequence, mech);
+
+ // Generates a NegTokenInit mechToken field for 1.2.3.4 mech
+ GSSHeader h1 = new GSSHeader(new ObjectIdentifier("1.2.3.4"), 1);
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ h1.encode(bout);
+ bout.write(new byte[1]);
+
+ // Generates the NegTokenInit token
+ Constructor<NegTokenInit> ctor = NegTokenInit.class.getDeclaredConstructor(
+ byte[].class, BitArray.class, byte[].class, byte[].class);
+ ctor.setAccessible(true);
+ NegTokenInit initToken = ctor.newInstance(
+ mechTypeList.toByteArray(),
+ new BitArray(0),
+ bout.toByteArray(),
+ null);
+ Method m = Class.forName("sun.security.jgss.spnego.SpNegoToken")
+ .getDeclaredMethod("getEncoded");
+ m.setAccessible(true);
+ byte[] spnegoToken = (byte[])m.invoke(initToken);
+
+ // and wraps it into a GSSToken
+ GSSHeader h = new GSSHeader(
+ new ObjectIdentifier(GSSUtil.GSS_SPNEGO_MECH_OID.toString()),
+ spnegoToken.length);
+ bout = new ByteArrayOutputStream();
+ h.encode(bout);
+ bout.write(spnegoToken);
+ byte[] token = bout.toByteArray();
+
+ // and feeds it to a GSS acceptor
+ GSSManager man = GSSManager.getInstance();
+ GSSContext ctxt = man.createContext((GSSCredential) null);
+ token = ctxt.acceptSecContext(token, 0, token.length);
+ NegTokenTarg targ = new NegTokenTarg(token);
+
+ // Make sure it's a GO-ON message
+ Method m2 = NegTokenTarg.class.getDeclaredMethod("getNegotiatedResult");
+ m2.setAccessible(true);
+ int negResult = (int)m2.invoke(targ);
+
+ if (negResult != 1 /* ACCEPT_INCOMPLETE */) {
+ throw new Exception("Not a continue");
+ }
+ }
+}
diff --git a/test/sun/text/resources/LocaleData b/test/sun/text/resources/LocaleData
index 9dca93b..f6439c2 100644
--- a/test/sun/text/resources/LocaleData
+++ b/test/sun/text/resources/LocaleData
@@ -2502,7 +2502,7 @@
CalendarData/pl_PL/minimalDaysInFirstWeek=4
CalendarData/pt_PT/minimalDaysInFirstWeek=4
-#bug 4945388
+#bug 4945388
CurrencyNames/be_BY/BYR=\u0420\u0443\u0431
CurrencyNames/bg_BG/BGN=\u043B\u0432.
@@ -5422,7 +5422,7 @@
FormatData/en_SG/DatePatterns/2=MMM d, yyyy
FormatData/en_SG/DatePatterns/3=M/d/yy
FormatData/en_SG/DateTimePatterns/0={1} {0}
-# Use approved data
+# Use approved data
FormatData/ms/Eras/0=BCE
FormatData/ms/Eras/1=CE
FormatData/sr_BA/MonthNames/5=\u0458\u0443\u043d\u0438
@@ -5571,7 +5571,7 @@
FormatData/fi/AmPmMarkers/0=ap.
FormatData/fi/AmPmMarkers/1=ip.
-# bug 6507067
+# bug 6507067
TimeZoneNames/zh_TW/Asia\/Taipei/1=\u53f0\u7063\u6a19\u6e96\u6642\u9593
TimeZoneNames/zh_TW/Asia\/Taipei/2=TST
@@ -7702,3 +7702,577 @@
# bug 8055222
CurrencyNames/lt_LT/EUR=\u20AC
+
+# bug 8042126 + missing MonthNarrows data
+FormatData//MonthNarrows/0=1
+FormatData//MonthNarrows/1=2
+FormatData//MonthNarrows/2=3
+FormatData//MonthNarrows/3=4
+FormatData//MonthNarrows/4=5
+FormatData//MonthNarrows/5=6
+FormatData//MonthNarrows/6=7
+FormatData//MonthNarrows/7=8
+FormatData//MonthNarrows/8=9
+FormatData//MonthNarrows/9=10
+FormatData//MonthNarrows/10=11
+FormatData//MonthNarrows/11=12
+FormatData//MonthNarrows/12=
+FormatData/bg/MonthNarrows/0=\u044f
+FormatData/bg/MonthNarrows/1=\u0444
+FormatData/bg/MonthNarrows/2=\u043c
+FormatData/bg/MonthNarrows/3=\u0430
+FormatData/bg/MonthNarrows/4=\u043c
+FormatData/bg/MonthNarrows/5=\u044e
+FormatData/bg/MonthNarrows/6=\u044e
+FormatData/bg/MonthNarrows/7=\u0430
+FormatData/bg/MonthNarrows/8=\u0441
+FormatData/bg/MonthNarrows/9=\u043e
+FormatData/bg/MonthNarrows/10=\u043d
+FormatData/bg/MonthNarrows/11=\u0434
+FormatData/bg/MonthNarrows/12=
+FormatData/zh_TW/MonthNarrows/0=1
+FormatData/zh_TW/MonthNarrows/1=2
+FormatData/zh_TW/MonthNarrows/2=3
+FormatData/zh_TW/MonthNarrows/3=4
+FormatData/zh_TW/MonthNarrows/4=5
+FormatData/zh_TW/MonthNarrows/5=6
+FormatData/zh_TW/MonthNarrows/6=7
+FormatData/zh_TW/MonthNarrows/7=8
+FormatData/zh_TW/MonthNarrows/8=9
+FormatData/zh_TW/MonthNarrows/9=10
+FormatData/zh_TW/MonthNarrows/10=11
+FormatData/zh_TW/MonthNarrows/11=12
+FormatData/zh_TW/MonthNarrows/12=
+FormatData/it/MonthNarrows/0=G
+FormatData/it/MonthNarrows/1=F
+FormatData/it/MonthNarrows/2=M
+FormatData/it/MonthNarrows/3=A
+FormatData/it/MonthNarrows/4=M
+FormatData/it/MonthNarrows/5=G
+FormatData/it/MonthNarrows/6=L
+FormatData/it/MonthNarrows/7=A
+FormatData/it/MonthNarrows/8=S
+FormatData/it/MonthNarrows/9=O
+FormatData/it/MonthNarrows/10=N
+FormatData/it/MonthNarrows/11=D
+FormatData/it/MonthNarrows/12=
+FormatData/ko/MonthNarrows/0=1\uc6d4
+FormatData/ko/MonthNarrows/1=2\uc6d4
+FormatData/ko/MonthNarrows/2=3\uc6d4
+FormatData/ko/MonthNarrows/3=4\uc6d4
+FormatData/ko/MonthNarrows/4=5\uc6d4
+FormatData/ko/MonthNarrows/5=6\uc6d4
+FormatData/ko/MonthNarrows/6=7\uc6d4
+FormatData/ko/MonthNarrows/7=8\uc6d4
+FormatData/ko/MonthNarrows/8=9\uc6d4
+FormatData/ko/MonthNarrows/9=10\uc6d4
+FormatData/ko/MonthNarrows/10=11\uc6d4
+FormatData/ko/MonthNarrows/11=12\uc6d4
+FormatData/ko/MonthNarrows/12=
+FormatData/uk/MonthNarrows/0=\u0421
+FormatData/uk/MonthNarrows/1=\u041b
+FormatData/uk/MonthNarrows/2=\u0411
+FormatData/uk/MonthNarrows/3=\u041a
+FormatData/uk/MonthNarrows/4=\u0422
+FormatData/uk/MonthNarrows/5=\u0427
+FormatData/uk/MonthNarrows/6=\u041b
+FormatData/uk/MonthNarrows/7=\u0421
+FormatData/uk/MonthNarrows/8=\u0412
+FormatData/uk/MonthNarrows/9=\u0416
+FormatData/uk/MonthNarrows/10=\u041b
+FormatData/uk/MonthNarrows/11=\u0413
+FormatData/uk/MonthNarrows/12=
+FormatData/lv/MonthNarrows/0=J
+FormatData/lv/MonthNarrows/1=F
+FormatData/lv/MonthNarrows/2=M
+FormatData/lv/MonthNarrows/3=A
+FormatData/lv/MonthNarrows/4=M
+FormatData/lv/MonthNarrows/5=J
+FormatData/lv/MonthNarrows/6=J
+FormatData/lv/MonthNarrows/7=A
+FormatData/lv/MonthNarrows/8=S
+FormatData/lv/MonthNarrows/9=O
+FormatData/lv/MonthNarrows/10=N
+FormatData/lv/MonthNarrows/11=D
+FormatData/lv/MonthNarrows/12=
+FormatData/pt/MonthNarrows/0=J
+FormatData/pt/MonthNarrows/1=F
+FormatData/pt/MonthNarrows/2=M
+FormatData/pt/MonthNarrows/3=A
+FormatData/pt/MonthNarrows/4=M
+FormatData/pt/MonthNarrows/5=J
+FormatData/pt/MonthNarrows/6=J
+FormatData/pt/MonthNarrows/7=A
+FormatData/pt/MonthNarrows/8=S
+FormatData/pt/MonthNarrows/9=O
+FormatData/pt/MonthNarrows/10=N
+FormatData/pt/MonthNarrows/11=D
+FormatData/pt/MonthNarrows/12=
+FormatData/sk/MonthNarrows/0=j
+FormatData/sk/MonthNarrows/1=f
+FormatData/sk/MonthNarrows/2=m
+FormatData/sk/MonthNarrows/3=a
+FormatData/sk/MonthNarrows/4=m
+FormatData/sk/MonthNarrows/5=j
+FormatData/sk/MonthNarrows/6=j
+FormatData/sk/MonthNarrows/7=a
+FormatData/sk/MonthNarrows/8=s
+FormatData/sk/MonthNarrows/9=o
+FormatData/sk/MonthNarrows/10=n
+FormatData/sk/MonthNarrows/11=d
+FormatData/sk/MonthNarrows/12=
+FormatData/hi_IN/MonthNarrows/0=\u091c
+FormatData/hi_IN/MonthNarrows/1=\u092b\u093c
+FormatData/hi_IN/MonthNarrows/2=\u092e\u093e
+FormatData/hi_IN/MonthNarrows/3=\u0905
+FormatData/hi_IN/MonthNarrows/4=\u092e
+FormatData/hi_IN/MonthNarrows/5=\u091c\u0942
+FormatData/hi_IN/MonthNarrows/6=\u091c\u0941
+FormatData/hi_IN/MonthNarrows/7=\u0905
+FormatData/hi_IN/MonthNarrows/8=\u0938\u093f
+FormatData/hi_IN/MonthNarrows/9=\u0905
+FormatData/hi_IN/MonthNarrows/10=\u0928
+FormatData/hi_IN/MonthNarrows/11=\u0926\u093f
+FormatData/hi_IN/MonthNarrows/12=
+FormatData/ga/MonthNarrows/0=E
+FormatData/ga/MonthNarrows/1=F
+FormatData/ga/MonthNarrows/2=M
+FormatData/ga/MonthNarrows/3=A
+FormatData/ga/MonthNarrows/4=B
+FormatData/ga/MonthNarrows/5=M
+FormatData/ga/MonthNarrows/6=I
+FormatData/ga/MonthNarrows/7=L
+FormatData/ga/MonthNarrows/8=M
+FormatData/ga/MonthNarrows/9=D
+FormatData/ga/MonthNarrows/10=S
+FormatData/ga/MonthNarrows/11=N
+FormatData/ga/MonthNarrows/12=
+FormatData/et/MonthNarrows/0=J
+FormatData/et/MonthNarrows/1=V
+FormatData/et/MonthNarrows/2=M
+FormatData/et/MonthNarrows/3=A
+FormatData/et/MonthNarrows/4=M
+FormatData/et/MonthNarrows/5=J
+FormatData/et/MonthNarrows/6=J
+FormatData/et/MonthNarrows/7=A
+FormatData/et/MonthNarrows/8=S
+FormatData/et/MonthNarrows/9=O
+FormatData/et/MonthNarrows/10=N
+FormatData/et/MonthNarrows/11=D
+FormatData/et/MonthNarrows/12=
+FormatData/sv/MonthNarrows/0=J
+FormatData/sv/MonthNarrows/1=F
+FormatData/sv/MonthNarrows/2=M
+FormatData/sv/MonthNarrows/3=A
+FormatData/sv/MonthNarrows/4=M
+FormatData/sv/MonthNarrows/5=J
+FormatData/sv/MonthNarrows/6=J
+FormatData/sv/MonthNarrows/7=A
+FormatData/sv/MonthNarrows/8=S
+FormatData/sv/MonthNarrows/9=O
+FormatData/sv/MonthNarrows/10=N
+FormatData/sv/MonthNarrows/11=D
+FormatData/sv/MonthNarrows/12=
+FormatData/cs/MonthNarrows/0=l
+FormatData/cs/MonthNarrows/1=\u00fa
+FormatData/cs/MonthNarrows/2=b
+FormatData/cs/MonthNarrows/3=d
+FormatData/cs/MonthNarrows/4=k
+FormatData/cs/MonthNarrows/5=\u010d
+FormatData/cs/MonthNarrows/6=\u010d
+FormatData/cs/MonthNarrows/7=s
+FormatData/cs/MonthNarrows/8=z
+FormatData/cs/MonthNarrows/9=\u0159
+FormatData/cs/MonthNarrows/10=l
+FormatData/cs/MonthNarrows/11=p
+FormatData/cs/MonthNarrows/12=
+FormatData/el/MonthNarrows/0=\u0399
+FormatData/el/MonthNarrows/1=\u03a6
+FormatData/el/MonthNarrows/2=\u039c
+FormatData/el/MonthNarrows/3=\u0391
+FormatData/el/MonthNarrows/4=\u039c
+FormatData/el/MonthNarrows/5=\u0399
+FormatData/el/MonthNarrows/6=\u0399
+FormatData/el/MonthNarrows/7=\u0391
+FormatData/el/MonthNarrows/8=\u03a3
+FormatData/el/MonthNarrows/9=\u039f
+FormatData/el/MonthNarrows/10=\u039d
+FormatData/el/MonthNarrows/11=\u0394
+FormatData/el/MonthNarrows/12=
+FormatData/hu/MonthNarrows/0=J
+FormatData/hu/MonthNarrows/1=F
+FormatData/hu/MonthNarrows/2=M
+FormatData/hu/MonthNarrows/3=\u00c1
+FormatData/hu/MonthNarrows/4=M
+FormatData/hu/MonthNarrows/5=J
+FormatData/hu/MonthNarrows/6=J
+FormatData/hu/MonthNarrows/7=A
+FormatData/hu/MonthNarrows/8=Sz
+FormatData/hu/MonthNarrows/9=O
+FormatData/hu/MonthNarrows/10=N
+FormatData/hu/MonthNarrows/11=D
+FormatData/hu/MonthNarrows/12=
+FormatData/es/MonthNarrows/0=E
+FormatData/es/MonthNarrows/1=F
+FormatData/es/MonthNarrows/2=M
+FormatData/es/MonthNarrows/3=A
+FormatData/es/MonthNarrows/4=M
+FormatData/es/MonthNarrows/5=J
+FormatData/es/MonthNarrows/6=J
+FormatData/es/MonthNarrows/7=A
+FormatData/es/MonthNarrows/8=S
+FormatData/es/MonthNarrows/9=O
+FormatData/es/MonthNarrows/10=N
+FormatData/es/MonthNarrows/11=D
+FormatData/es/MonthNarrows/12=
+FormatData/tr/MonthNarrows/0=O
+FormatData/tr/MonthNarrows/1=\u015e
+FormatData/tr/MonthNarrows/2=M
+FormatData/tr/MonthNarrows/3=N
+FormatData/tr/MonthNarrows/4=M
+FormatData/tr/MonthNarrows/5=H
+FormatData/tr/MonthNarrows/6=T
+FormatData/tr/MonthNarrows/7=A
+FormatData/tr/MonthNarrows/8=E
+FormatData/tr/MonthNarrows/9=E
+FormatData/tr/MonthNarrows/10=K
+FormatData/tr/MonthNarrows/11=A
+FormatData/tr/MonthNarrows/12=
+FormatData/hr/MonthNarrows/0=1.
+FormatData/hr/MonthNarrows/1=2.
+FormatData/hr/MonthNarrows/2=3.
+FormatData/hr/MonthNarrows/3=4.
+FormatData/hr/MonthNarrows/4=5.
+FormatData/hr/MonthNarrows/5=6.
+FormatData/hr/MonthNarrows/6=7.
+FormatData/hr/MonthNarrows/7=8.
+FormatData/hr/MonthNarrows/8=9.
+FormatData/hr/MonthNarrows/9=10.
+FormatData/hr/MonthNarrows/10=11.
+FormatData/hr/MonthNarrows/11=12.
+FormatData/hr/MonthNarrows/12=
+FormatData/lt/MonthNarrows/0=S
+FormatData/lt/MonthNarrows/1=V
+FormatData/lt/MonthNarrows/2=K
+FormatData/lt/MonthNarrows/3=B
+FormatData/lt/MonthNarrows/4=G
+FormatData/lt/MonthNarrows/5=B
+FormatData/lt/MonthNarrows/6=L
+FormatData/lt/MonthNarrows/7=R
+FormatData/lt/MonthNarrows/8=R
+FormatData/lt/MonthNarrows/9=S
+FormatData/lt/MonthNarrows/10=L
+FormatData/lt/MonthNarrows/11=G
+FormatData/lt/MonthNarrows/12=
+FormatData/sq/MonthNarrows/0=J
+FormatData/sq/MonthNarrows/1=S
+FormatData/sq/MonthNarrows/2=M
+FormatData/sq/MonthNarrows/3=P
+FormatData/sq/MonthNarrows/4=M
+FormatData/sq/MonthNarrows/5=Q
+FormatData/sq/MonthNarrows/6=K
+FormatData/sq/MonthNarrows/7=G
+FormatData/sq/MonthNarrows/8=S
+FormatData/sq/MonthNarrows/9=T
+FormatData/sq/MonthNarrows/10=N
+FormatData/sq/MonthNarrows/11=D
+FormatData/sq/MonthNarrows/12=
+FormatData/fr/MonthNarrows/0=J
+FormatData/fr/MonthNarrows/1=F
+FormatData/fr/MonthNarrows/2=M
+FormatData/fr/MonthNarrows/3=A
+FormatData/fr/MonthNarrows/4=M
+FormatData/fr/MonthNarrows/5=J
+FormatData/fr/MonthNarrows/6=J
+FormatData/fr/MonthNarrows/7=A
+FormatData/fr/MonthNarrows/8=S
+FormatData/fr/MonthNarrows/9=O
+FormatData/fr/MonthNarrows/10=N
+FormatData/fr/MonthNarrows/11=D
+FormatData/fr/MonthNarrows/12=
+FormatData/is/MonthNarrows/0=J
+FormatData/is/MonthNarrows/1=F
+FormatData/is/MonthNarrows/2=M
+FormatData/is/MonthNarrows/3=A
+FormatData/is/MonthNarrows/4=M
+FormatData/is/MonthNarrows/5=J
+FormatData/is/MonthNarrows/6=J
+FormatData/is/MonthNarrows/7=\u00c1
+FormatData/is/MonthNarrows/8=L
+FormatData/is/MonthNarrows/9=O
+FormatData/is/MonthNarrows/10=N
+FormatData/is/MonthNarrows/11=D
+FormatData/is/MonthNarrows/12=
+FormatData/de/MonthNarrows/0=J
+FormatData/de/MonthNarrows/1=F
+FormatData/de/MonthNarrows/2=M
+FormatData/de/MonthNarrows/3=A
+FormatData/de/MonthNarrows/4=M
+FormatData/de/MonthNarrows/5=J
+FormatData/de/MonthNarrows/6=J
+FormatData/de/MonthNarrows/7=A
+FormatData/de/MonthNarrows/8=S
+FormatData/de/MonthNarrows/9=O
+FormatData/de/MonthNarrows/10=N
+FormatData/de/MonthNarrows/11=D
+FormatData/de/MonthNarrows/12=
+FormatData/en/MonthNarrows/0=J
+FormatData/en/MonthNarrows/1=F
+FormatData/en/MonthNarrows/2=M
+FormatData/en/MonthNarrows/3=A
+FormatData/en/MonthNarrows/4=M
+FormatData/en/MonthNarrows/5=J
+FormatData/en/MonthNarrows/6=J
+FormatData/en/MonthNarrows/7=A
+FormatData/en/MonthNarrows/8=S
+FormatData/en/MonthNarrows/9=O
+FormatData/en/MonthNarrows/10=N
+FormatData/en/MonthNarrows/11=D
+FormatData/en/MonthNarrows/12=
+FormatData/ca/MonthNarrows/0=G
+FormatData/ca/MonthNarrows/1=F
+FormatData/ca/MonthNarrows/2=M
+FormatData/ca/MonthNarrows/3=A
+FormatData/ca/MonthNarrows/4=M
+FormatData/ca/MonthNarrows/5=J
+FormatData/ca/MonthNarrows/6=G
+FormatData/ca/MonthNarrows/7=A
+FormatData/ca/MonthNarrows/8=S
+FormatData/ca/MonthNarrows/9=O
+FormatData/ca/MonthNarrows/10=N
+FormatData/ca/MonthNarrows/11=D
+FormatData/ca/MonthNarrows/12=
+FormatData/sl/MonthNarrows/0=j
+FormatData/sl/MonthNarrows/1=f
+FormatData/sl/MonthNarrows/2=m
+FormatData/sl/MonthNarrows/3=a
+FormatData/sl/MonthNarrows/4=m
+FormatData/sl/MonthNarrows/5=j
+FormatData/sl/MonthNarrows/6=j
+FormatData/sl/MonthNarrows/7=a
+FormatData/sl/MonthNarrows/8=s
+FormatData/sl/MonthNarrows/9=o
+FormatData/sl/MonthNarrows/10=n
+FormatData/sl/MonthNarrows/11=d
+FormatData/sl/MonthNarrows/12=
+FormatData/fi/MonthNarrows/0=T
+FormatData/fi/MonthNarrows/1=H
+FormatData/fi/MonthNarrows/2=M
+FormatData/fi/MonthNarrows/3=H
+FormatData/fi/MonthNarrows/4=T
+FormatData/fi/MonthNarrows/5=K
+FormatData/fi/MonthNarrows/6=H
+FormatData/fi/MonthNarrows/7=E
+FormatData/fi/MonthNarrows/8=S
+FormatData/fi/MonthNarrows/9=L
+FormatData/fi/MonthNarrows/10=M
+FormatData/fi/MonthNarrows/11=J
+FormatData/fi/MonthNarrows/12=
+FormatData/mk/MonthNarrows/0=\u0458
+FormatData/mk/MonthNarrows/1=\u0444
+FormatData/mk/MonthNarrows/2=\u043c
+FormatData/mk/MonthNarrows/3=\u0430
+FormatData/mk/MonthNarrows/4=\u043c
+FormatData/mk/MonthNarrows/5=\u0458
+FormatData/mk/MonthNarrows/6=\u0458
+FormatData/mk/MonthNarrows/7=\u0430
+FormatData/mk/MonthNarrows/8=\u0441
+FormatData/mk/MonthNarrows/9=\u043e
+FormatData/mk/MonthNarrows/10=\u043d
+FormatData/mk/MonthNarrows/11=\u0434
+FormatData/mk/MonthNarrows/12=
+FormatData/sr-Latn/MonthNarrows/0=j
+FormatData/sr-Latn/MonthNarrows/1=f
+FormatData/sr-Latn/MonthNarrows/2=m
+FormatData/sr-Latn/MonthNarrows/3=a
+FormatData/sr-Latn/MonthNarrows/4=m
+FormatData/sr-Latn/MonthNarrows/5=j
+FormatData/sr-Latn/MonthNarrows/6=j
+FormatData/sr-Latn/MonthNarrows/7=a
+FormatData/sr-Latn/MonthNarrows/8=s
+FormatData/sr-Latn/MonthNarrows/9=o
+FormatData/sr-Latn/MonthNarrows/10=n
+FormatData/sr-Latn/MonthNarrows/11=d
+FormatData/sr-Latn/MonthNarrows/12=
+FormatData/th/MonthNarrows/0=\u0e21.\u0e04.
+FormatData/th/MonthNarrows/1=\u0e01.\u0e1e.
+FormatData/th/MonthNarrows/2=\u0e21\u0e35.\u0e04.
+FormatData/th/MonthNarrows/3=\u0e40\u0e21.\u0e22.
+FormatData/th/MonthNarrows/4=\u0e1e.\u0e04.
+FormatData/th/MonthNarrows/5=\u0e21\u0e34.\u0e22
+FormatData/th/MonthNarrows/6=\u0e01.\u0e04.
+FormatData/th/MonthNarrows/7=\u0e2a.\u0e04.
+FormatData/th/MonthNarrows/8=\u0e01.\u0e22.
+FormatData/th/MonthNarrows/9=\u0e15.\u0e04.
+FormatData/th/MonthNarrows/10=\u0e1e.\u0e22.
+FormatData/th/MonthNarrows/11=\u0e18.\u0e04.
+FormatData/th/MonthNarrows/12=
+FormatData/ar/MonthNarrows/0=\u064a
+FormatData/ar/MonthNarrows/1=\u0641
+FormatData/ar/MonthNarrows/2=\u0645
+FormatData/ar/MonthNarrows/3=\u0623
+FormatData/ar/MonthNarrows/4=\u0648
+FormatData/ar/MonthNarrows/5=\u0646
+FormatData/ar/MonthNarrows/6=\u0644
+FormatData/ar/MonthNarrows/7=\u063a
+FormatData/ar/MonthNarrows/8=\u0633
+FormatData/ar/MonthNarrows/9=\u0643
+FormatData/ar/MonthNarrows/10=\u0628
+FormatData/ar/MonthNarrows/11=\u062f
+FormatData/ar/MonthNarrows/12=
+FormatData/ru/MonthNarrows/0=\u042f
+FormatData/ru/MonthNarrows/1=\u0424
+FormatData/ru/MonthNarrows/2=\u041c
+FormatData/ru/MonthNarrows/3=\u0410
+FormatData/ru/MonthNarrows/4=\u041c
+FormatData/ru/MonthNarrows/5=\u0418
+FormatData/ru/MonthNarrows/6=\u0418
+FormatData/ru/MonthNarrows/7=\u0410
+FormatData/ru/MonthNarrows/8=\u0421
+FormatData/ru/MonthNarrows/9=\u041e
+FormatData/ru/MonthNarrows/10=\u041d
+FormatData/ru/MonthNarrows/11=\u0414
+FormatData/ru/MonthNarrows/12=
+FormatData/ms/MonthNarrows/0=J
+FormatData/ms/MonthNarrows/1=F
+FormatData/ms/MonthNarrows/2=M
+FormatData/ms/MonthNarrows/3=A
+FormatData/ms/MonthNarrows/4=M
+FormatData/ms/MonthNarrows/5=J
+FormatData/ms/MonthNarrows/6=J
+FormatData/ms/MonthNarrows/7=O
+FormatData/ms/MonthNarrows/8=S
+FormatData/ms/MonthNarrows/9=O
+FormatData/ms/MonthNarrows/10=N
+FormatData/ms/MonthNarrows/11=D
+FormatData/ms/MonthNarrows/12=
+FormatData/nl/MonthNarrows/0=J
+FormatData/nl/MonthNarrows/1=F
+FormatData/nl/MonthNarrows/2=M
+FormatData/nl/MonthNarrows/3=A
+FormatData/nl/MonthNarrows/4=M
+FormatData/nl/MonthNarrows/5=J
+FormatData/nl/MonthNarrows/6=J
+FormatData/nl/MonthNarrows/7=A
+FormatData/nl/MonthNarrows/8=S
+FormatData/nl/MonthNarrows/9=O
+FormatData/nl/MonthNarrows/10=N
+FormatData/nl/MonthNarrows/11=D
+FormatData/nl/MonthNarrows/12=
+FormatData/vi/MonthNarrows/0=1
+FormatData/vi/MonthNarrows/1=2
+FormatData/vi/MonthNarrows/2=3
+FormatData/vi/MonthNarrows/3=4
+FormatData/vi/MonthNarrows/4=5
+FormatData/vi/MonthNarrows/5=6
+FormatData/vi/MonthNarrows/6=7
+FormatData/vi/MonthNarrows/7=8
+FormatData/vi/MonthNarrows/8=9
+FormatData/vi/MonthNarrows/9=10
+FormatData/vi/MonthNarrows/10=11
+FormatData/vi/MonthNarrows/11=12
+FormatData/vi/MonthNarrows/12=
+FormatData/sr/MonthNarrows/0=\u0458
+FormatData/sr/MonthNarrows/1=\u0444
+FormatData/sr/MonthNarrows/2=\u043c
+FormatData/sr/MonthNarrows/3=\u0430
+FormatData/sr/MonthNarrows/4=\u043c
+FormatData/sr/MonthNarrows/5=\u0458
+FormatData/sr/MonthNarrows/6=\u0458
+FormatData/sr/MonthNarrows/7=\u0430
+FormatData/sr/MonthNarrows/8=\u0441
+FormatData/sr/MonthNarrows/9=\u043e
+FormatData/sr/MonthNarrows/10=\u043d
+FormatData/sr/MonthNarrows/11=\u0434
+FormatData/sr/MonthNarrows/12=
+FormatData/mt/MonthNarrows/0=J
+FormatData/mt/MonthNarrows/1=F
+FormatData/mt/MonthNarrows/2=M
+FormatData/mt/MonthNarrows/3=A
+FormatData/mt/MonthNarrows/4=M
+FormatData/mt/MonthNarrows/5=\u0120
+FormatData/mt/MonthNarrows/6=L
+FormatData/mt/MonthNarrows/7=A
+FormatData/mt/MonthNarrows/8=S
+FormatData/mt/MonthNarrows/9=O
+FormatData/mt/MonthNarrows/10=N
+FormatData/mt/MonthNarrows/11=D
+FormatData/mt/MonthNarrows/12=
+FormatData/da/MonthNarrows/0=J
+FormatData/da/MonthNarrows/1=F
+FormatData/da/MonthNarrows/2=M
+FormatData/da/MonthNarrows/3=A
+FormatData/da/MonthNarrows/4=M
+FormatData/da/MonthNarrows/5=J
+FormatData/da/MonthNarrows/6=J
+FormatData/da/MonthNarrows/7=A
+FormatData/da/MonthNarrows/8=S
+FormatData/da/MonthNarrows/9=O
+FormatData/da/MonthNarrows/10=N
+FormatData/da/MonthNarrows/11=D
+FormatData/da/MonthNarrows/12=
+FormatData/ro/MonthNarrows/0=I
+FormatData/ro/MonthNarrows/1=F
+FormatData/ro/MonthNarrows/2=M
+FormatData/ro/MonthNarrows/3=A
+FormatData/ro/MonthNarrows/4=M
+FormatData/ro/MonthNarrows/5=I
+FormatData/ro/MonthNarrows/6=I
+FormatData/ro/MonthNarrows/7=A
+FormatData/ro/MonthNarrows/8=S
+FormatData/ro/MonthNarrows/9=O
+FormatData/ro/MonthNarrows/10=N
+FormatData/ro/MonthNarrows/11=D
+FormatData/ro/MonthNarrows/12=
+FormatData/no/MonthNarrows/0=J
+FormatData/no/MonthNarrows/1=F
+FormatData/no/MonthNarrows/2=M
+FormatData/no/MonthNarrows/3=A
+FormatData/no/MonthNarrows/4=M
+FormatData/no/MonthNarrows/5=J
+FormatData/no/MonthNarrows/6=J
+FormatData/no/MonthNarrows/7=A
+FormatData/no/MonthNarrows/8=S
+FormatData/no/MonthNarrows/9=O
+FormatData/no/MonthNarrows/10=N
+FormatData/no/MonthNarrows/11=D
+FormatData/no/MonthNarrows/12=
+FormatData/pl/MonthNarrows/0=s
+FormatData/pl/MonthNarrows/1=l
+FormatData/pl/MonthNarrows/2=m
+FormatData/pl/MonthNarrows/3=k
+FormatData/pl/MonthNarrows/4=m
+FormatData/pl/MonthNarrows/5=c
+FormatData/pl/MonthNarrows/6=l
+FormatData/pl/MonthNarrows/7=s
+FormatData/pl/MonthNarrows/8=w
+FormatData/pl/MonthNarrows/9=p
+FormatData/pl/MonthNarrows/10=l
+FormatData/pl/MonthNarrows/11=g
+FormatData/pl/MonthNarrows/12=
+FormatData/iw/MonthNarrows/0=1
+FormatData/iw/MonthNarrows/1=2
+FormatData/iw/MonthNarrows/2=3
+FormatData/iw/MonthNarrows/3=4
+FormatData/iw/MonthNarrows/4=5
+FormatData/iw/MonthNarrows/5=6
+FormatData/iw/MonthNarrows/6=7
+FormatData/iw/MonthNarrows/7=8
+FormatData/iw/MonthNarrows/8=9
+FormatData/iw/MonthNarrows/9=10
+FormatData/iw/MonthNarrows/10=11
+FormatData/iw/MonthNarrows/11=12
+FormatData/iw/MonthNarrows/12=
+FormatData/zh/MonthNarrows/0=1
+FormatData/zh/MonthNarrows/1=2
+FormatData/zh/MonthNarrows/2=3
+FormatData/zh/MonthNarrows/3=4
+FormatData/zh/MonthNarrows/4=5
+FormatData/zh/MonthNarrows/5=6
+FormatData/zh/MonthNarrows/6=7
+FormatData/zh/MonthNarrows/7=8
+FormatData/zh/MonthNarrows/8=9
+FormatData/zh/MonthNarrows/9=10
+FormatData/zh/MonthNarrows/10=11
+FormatData/zh/MonthNarrows/11=12
+FormatData/zh/MonthNarrows/12=
diff --git a/test/sun/text/resources/LocaleDataTest.java b/test/sun/text/resources/LocaleDataTest.java
index e2cea1a..6ac5dc5 100644
--- a/test/sun/text/resources/LocaleDataTest.java
+++ b/test/sun/text/resources/LocaleDataTest.java
@@ -36,7 +36,7 @@
* 6919624 6998391 7019267 7020960 7025837 7020583 7036905 7066203 7101495
* 7003124 7085757 7028073 7171028 7189611 8000983 7195759 8004489 8006509
* 7114053 7074882 7040556 8013836 8021121 6192407 6931564 8027695 7090826
- * 8017142 8037343 8055222
+ * 8017142 8037343 8055222 8042126
* @summary Verify locale data
*
*/