Mercurial > hg > shenandoah-preopenjdk-archive > openjdk8 > jdk
changeset 10187:c3a4729c70fa jdk8u40-b10
Merge
author | asaha |
---|---|
date | Tue, 14 Oct 2014 10:22:21 -0700 |
parents | ea780a99f132 (current diff) d0755381deda (diff) |
children | 693da296b395 |
files | src/share/classes/com/sun/jarsigner/package.html src/share/classes/java/security/Signature.java src/windows/native/sun/windows/awt_Component.cpp |
diffstat | 85 files changed, 5270 insertions(+), 2245 deletions(-) [+] |
line wrap: on
line diff
--- a/make/data/jdwp/jdwp.spec Wed Oct 08 14:15:17 2014 -0700 +++ b/make/data/jdwp/jdwp.spec Tue Oct 14 10:22:21 2014 -0700 @@ -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)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/back/InterfaceTypeImpl.c Tue Oct 14 10:22:21 2014 -0700 @@ -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 +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/back/InterfaceTypeImpl.h Tue Oct 14 10:22:21 2014 -0700 @@ -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[];
--- a/src/share/back/VirtualMachineImpl.c Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/back/VirtualMachineImpl.c Tue Oct 14 10:22:21 2014 -0700 @@ -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)
--- a/src/share/back/debugDispatch.c Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/back/debugDispatch.c Tue Oct 14 10:22:21 2014 -0700 @@ -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;
--- a/src/share/back/util.c Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/back/util.c Tue Oct 14 10:22:21 2014 -0700 @@ -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 {
--- a/src/share/classes/com/sun/jarsigner/ContentSigner.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/jarsigner/ContentSigner.java Tue Oct 14 10:22:21 2014 -0700 @@ -37,6 +37,7 @@ * @author Vincent Ryan */ +@jdk.Exported public abstract class ContentSigner { /**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/jarsigner/package-info.java Tue Oct 14 10:22:21 2014 -0700 @@ -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;
--- a/src/share/classes/com/sun/jarsigner/package.html Wed Oct 08 14:15:17 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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>
--- a/src/share/classes/com/sun/java/util/jar/pack/DriverResource_ja.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/java/util/jar/pack/DriverResource_ja.java Tue Oct 14 10:22:21 2014 -0700 @@ -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",
--- a/src/share/classes/com/sun/jdi/ClassType.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/jdi/ClassType.java Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- a/src/share/classes/com/sun/jdi/InterfaceType.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/jdi/InterfaceType.java Tue Oct 14 10:22:21 2014 -0700 @@ -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(); + } }
--- a/src/share/classes/com/sun/jdi/Method.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/jdi/Method.java Tue Oct 14 10:22:21 2014 -0700 @@ -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;
--- a/src/share/classes/com/sun/jdi/ObjectReference.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/jdi/ObjectReference.java Tue Oct 14 10:22:21 2014 -0700 @@ -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.
--- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ja.properties Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_ko.properties Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_CN.properties Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- a/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_zh_TW.properties Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- a/src/share/classes/com/sun/tools/example/debug/expr/LValue.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/tools/example/debug/expr/LValue.java Tue Oct 14 10:22:21 2014 -0700 @@ -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());
--- a/src/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java Tue Oct 14 10:22:21 2014 -0700 @@ -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 }
--- a/src/share/classes/com/sun/tools/jdi/ClassTypeImpl.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/tools/jdi/ClassTypeImpl.java Tue Oct 14 10:22:21 2014 -0700 @@ -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); + } }
--- a/src/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/tools/jdi/InterfaceTypeImpl.java Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/classes/com/sun/tools/jdi/InvokableTypeImpl.java Tue Oct 14 10:22:21 2014 -0700 @@ -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); +}
--- a/src/share/classes/com/sun/tools/jdi/MethodImpl.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/tools/jdi/MethodImpl.java Tue Oct 14 10:22:21 2014 -0700 @@ -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); }
--- a/src/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java Tue Oct 14 10:22:21 2014 -0700 @@ -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 {
--- a/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- a/src/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/com/sun/tools/jdi/VirtualMachineManagerImpl.java Tue Oct 14 10:22:21 2014 -0700 @@ -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;
--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Tue Oct 14 10:22:21 2014 -0700 @@ -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;
--- a/src/share/classes/java/net/URLClassLoader.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/net/URLClassLoader.java Tue Oct 14 10:22:21 2014 -0700 @@ -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; } /*
--- a/src/share/classes/java/security/KeyPairGenerator.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/security/KeyPairGenerator.java Tue Oct 14 10:22:21 2014 -0700 @@ -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()); + } } /**
--- a/src/share/classes/java/security/KeyStore.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/security/KeyStore.java Tue Oct 14 10:22:21 2014 -0700 @@ -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()); + } } /**
--- a/src/share/classes/java/security/MessageDigest.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/security/MessageDigest.java Tue Oct 14 10:22:21 2014 -0700 @@ -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"); }
--- a/src/share/classes/java/security/SecureRandom.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/security/SecureRandom.java Tue Oct 14 10:22:21 2014 -0700 @@ -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()); + } } /**
--- a/src/share/classes/java/security/Signature.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/security/Signature.java Tue Oct 14 10:22:21 2014 -0700 @@ -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()); + } } /**
--- a/src/share/classes/java/util/concurrent/ForkJoinPool.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/util/concurrent/ForkJoinPool.java Tue Oct 14 10:22:21 2014 -0700 @@ -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. + * + * 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. * - * 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" + * 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 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; + } + } + else + pollAndExecAll(); + } + } + + /** + * Executes the given task and any remaining local tasks. */ 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; - t.doExec(); - } - } - if ((thread = owner) != null) // no need to do in finally clause + 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) - empty = false; - else if (s + 1 == top) { // pop and throw away - if (U.compareAndSwapObject(a, j, t, null)) - top = s; - 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; } - 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) { - 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) { - if (base == b && - U.compareAndSwapObject(a, j, t, null)) { - U.putOrderedInt(this, QBASE, b + 1); - t.doExec(); - } - 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; + 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.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(); + 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 - qlock = 0; } - return true; + else if (U.compareAndSwapObject(a, j, t, null)) { + U.putOrderedInt(this, QTOP, s - 1); + return t; + } + break; } - else if ((r = r.completer) == null) + else if ((r = r.completer) == null) // try parent break; } } } - return false; + return null; } /** - * Internal version + * 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 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; + 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) + 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)) { + base = b + 1; t.doExec(); + h = 1; // success } - return true; + else + h = 2; // lost CAS + break; } - 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 - * - * 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) + * 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 * - * 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 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 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 - private static final int AC_SHIFT = 48; - private static final int TC_SHIFT = 32; - private static final int ST_SHIFT = 31; - private static final int EC_SHIFT = 16; + // Lower and upper word masks + private static final long SP_MASK = 0xffffffffL; + private static final long UC_MASK = ~SP_MASK; - // 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; + // 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; - // 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; + // Total counts + private static final int TC_SHIFT = 32; + 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 - // 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 runState lock; returns current (locked) runState. + */ + private int lockRunState() { + int rs; + return ((((rs = runState) & RSLOCK) != 0 || + !U.compareAndSwapInt(this, RUNSTATE, rs, rs |= RSLOCK)) ? + awaitRunStateLock() : rs); + } /** - * 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. + * Spins and/or blocks until runstate lock is available. See + * above for explanation. */ - 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 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(); } + 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(); } + } + } + + // Creating, registering and deregistering workers + + /** + * 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 create and start one worker if fewer than target - * parallelism level exist. Adjusts counts etc on failure. + * 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; 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; + 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; } - deregisterWorker(wt, ex); - break; } - } + } while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0); } - // 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. + * 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(); + (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 + } + 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 refs on way out + 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; + if (ws.length <= (i = sp & SMASK)) // terminated + break; + if ((v = ws[i]) == null) // terminating 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) + 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 on common pool + // External operations /** - * Returns common pool queue for a thread that has submitted at - * least one task. + * 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. */ - static WorkQueue commonSubmitterQueue() { - ForkJoinPool p; WorkQueue[] ws; int m, z; - return ((z = ThreadLocalRandom.getProbe()) != 0 && - (p = common) != null && - (ws = p.workQueues) != null && - (m = ws.length - 1) >= 0) ? - ws[m & z & SQMASK] : 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); + } } /** - * Tries to pop the given task from submitter's queue in 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 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) { - 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 && - U.compareAndSwapObject(a, j, task, null)) { - joiner.top = s - 1; - popped = true; - } - joiner.qlock = 0; + 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); } - return popped; + externalSubmit(task); } - 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; + /** + * Returns common pool queue for an external thread. + */ + static WorkQueue commonSubmitterQueue() { + 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 & r & SQMASK] : null; + } + + /** + * 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[] 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.compareAndSwapInt(w, QLOCK, 0, 1)) { + if (w.top == s && w.array == a && + U.getObject(a, j) == task && + U.compareAndSwapObject(a, j, task, null)) { + U.putOrderedInt(w, QTOP, s - 1); + U.putOrderedInt(w, QLOCK, 0); + return true; } - 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; - } + U.compareAndSwapInt(w, QLOCK, 1, 0); } } - return s; + return false; + } + + /** + * Performs helpComplete for an external submitter. + */ + final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) { + 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; }
--- a/src/share/classes/java/util/concurrent/ForkJoinTask.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/util/concurrent/ForkJoinTask.java Tue Oct 14 10:22:21 2014 -0700 @@ -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 - } - else if ((cp = ForkJoinPool.common) != null) { - if (this instanceof CountedCompleter) - cp.externalHelpComplete((CountedCompleter<?>)this, Integer.MAX_VALUE); - else if (cp.tryExternalUnpush(this)) - doExec(); + s = wt.pool.awaitJoin(wt.workQueue, this, deadline); } - 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)
--- a/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java Tue Oct 14 10:22:21 2014 -0700 @@ -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 @@ } } -
--- a/src/share/classes/java/util/logging/FileHandler.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/java/util/logging/FileHandler.java Tue Oct 14 10:22:21 2014 -0700 @@ -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);
--- a/src/share/classes/javax/crypto/Cipher.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/javax/crypto/Cipher.java Tue Oct 14 10:22:21 2014 -0700 @@ -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()); + } } /**
--- a/src/share/classes/javax/crypto/KeyAgreement.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/javax/crypto/KeyAgreement.java Tue Oct 14 10:22:21 2014 -0700 @@ -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()); + } } /**
--- a/src/share/classes/javax/crypto/KeyGenerator.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/javax/crypto/KeyGenerator.java Tue Oct 14 10:22:21 2014 -0700 @@ -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()); + } } /**
--- a/src/share/classes/javax/crypto/Mac.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/javax/crypto/Mac.java Tue Oct 14 10:22:21 2014 -0700 @@ -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()); + } } /**
--- a/src/share/classes/sun/awt/datatransfer/DataTransferer.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/awt/datatransfer/DataTransferer.java Tue Oct 14 10:22:21 2014 -0700 @@ -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.
--- a/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java Tue Oct 14 10:22:21 2014 -0700 @@ -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)
--- a/src/share/classes/sun/security/tools/keytool/Resources.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources.java Tue Oct 14 10:22:21 2014 -0700 @@ -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: "},
--- a/src/share/classes/sun/security/tools/keytool/Resources_de.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources_de.java Tue Oct 14 10:22:21 2014 -0700 @@ -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: "},
--- a/src/share/classes/sun/security/tools/keytool/Resources_es.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources_es.java Tue Oct 14 10:22:21 2014 -0700 @@ -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}: "},
--- a/src/share/classes/sun/security/tools/keytool/Resources_fr.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources_fr.java Tue Oct 14 10:22:21 2014 -0700 @@ -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} : "},
--- a/src/share/classes/sun/security/tools/keytool/Resources_it.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources_it.java Tue Oct 14 10:22:21 2014 -0700 @@ -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}: "},
--- a/src/share/classes/sun/security/tools/keytool/Resources_ja.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources_ja.java Tue Oct 14 10:22:21 2014 -0700 @@ -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: "},
--- a/src/share/classes/sun/security/tools/keytool/Resources_ko.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources_ko.java Tue Oct 14 10:22:21 2014 -0700 @@ -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: "},
--- a/src/share/classes/sun/security/tools/keytool/Resources_pt_BR.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources_pt_BR.java Tue Oct 14 10:22:21 2014 -0700 @@ -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}: "},
--- a/src/share/classes/sun/security/tools/keytool/Resources_sv.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources_sv.java Tue Oct 14 10:22:21 2014 -0700 @@ -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}: "},
--- a/src/share/classes/sun/security/tools/keytool/Resources_zh_CN.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources_zh_CN.java Tue Oct 14 10:22:21 2014 -0700 @@ -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: "},
--- a/src/share/classes/sun/security/tools/keytool/Resources_zh_TW.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/tools/keytool/Resources_zh_TW.java Tue Oct 14 10:22:21 2014 -0700 @@ -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: "},
--- a/src/share/classes/sun/security/util/Debug.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/security/util/Debug.java Tue Oct 14 10:22:21 2014 -0700 @@ -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);
--- a/src/share/classes/sun/text/resources/FormatData.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/text/resources/FormatData.java Tue Oct 14 10:22:21 2014 -0700 @@ -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", "", } },
--- a/src/share/classes/sun/text/resources/en/FormatData_en.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/classes/sun/text/resources/en/FormatData_en.java Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- a/src/share/native/sun/security/ec/ECC_JNI.cpp Wed Oct 08 14:15:17 2014 -0700 +++ b/src/share/native/sun/security/ec/ECC_JNI.cpp Tue Oct 14 10:22:21 2014 -0700 @@ -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,
--- a/src/solaris/classes/sun/awt/X11/XRootWindow.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/solaris/classes/sun/awt/X11/XRootWindow.java Tue Oct 14 10:22:21 2014 -0700 @@ -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){
--- a/src/solaris/classes/sun/awt/X11/XToolkit.java Wed Oct 08 14:15:17 2014 -0700 +++ b/src/solaris/classes/sun/awt/X11/XToolkit.java Tue Oct 14 10:22:21 2014 -0700 @@ -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");
--- a/src/solaris/native/sun/awt/awt_util.h Wed Oct 08 14:15:17 2014 -0700 +++ b/src/solaris/native/sun/awt/awt_util.h Tue Oct 14 10:22:21 2014 -0700 @@ -52,6 +52,8 @@ */ extern XErrorHandler current_native_xerror_handler; +Window get_xawt_root_shell(JNIEnv *env); + #endif /* !HEADLESS */ #ifndef INTERSECTS
--- a/src/solaris/native/sun/xawt/XlibWrapper.c Wed Oct 08 14:15:17 2014 -0700 +++ b/src/solaris/native/sun/xawt/XlibWrapper.c Tue Oct 14 10:22:21 2014 -0700 @@ -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;
--- a/src/windows/native/sun/java2d/windows/GDIRenderer.cpp Wed Oct 08 14:15:17 2014 -0700 +++ b/src/windows/native/sun/java2d/windows/GDIRenderer.cpp Tue Oct 14 10:22:21 2014 -0700 @@ -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); }
--- a/src/windows/native/sun/security/mscapi/security.cpp Wed Oct 08 14:15:17 2014 -0700 +++ b/src/windows/native/sun/security/mscapi/security.cpp Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- a/src/windows/native/sun/windows/awt_TextArea.cpp Wed Oct 08 14:15:17 2014 -0700 +++ b/src/windows/native/sun/windows/awt_TextArea.cpp Tue Oct 14 10:22:21 2014 -0700 @@ -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); }
--- a/src/windows/native/sun/windows/awt_TextArea.h Wed Oct 08 14:15:17 2014 -0700 +++ b/src/windows/native/sun/windows/awt_TextArea.h Tue Oct 14 10:22:21 2014 -0700 @@ -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;
--- a/src/windows/native/sun/windows/awt_TextComponent.cpp Wed Oct 08 14:15:17 2014 -0700 +++ b/src/windows/native/sun/windows/awt_TextComponent.cpp Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- a/src/windows/native/sun/windows/awt_TextComponent.h Wed Oct 08 14:15:17 2014 -0700 +++ b/src/windows/native/sun/windows/awt_TextComponent.h Tue Oct 14 10:22:21 2014 -0700 @@ -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 //
--- a/src/windows/native/sun/windows/awt_TextField.cpp Wed Oct 08 14:15:17 2014 -0700 +++ b/src/windows/native/sun/windows/awt_TextField.cpp Tue Oct 14 10:22:21 2014 -0700 @@ -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);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/com/sun/jdi/EvalInterfaceStatic.sh Tue Oct 14 10:22:21 2014 -0700 @@ -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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/com/sun/jdi/InterfaceMethodsTest.java Tue Oct 14 10:22:21 2014 -0700 @@ -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); + } + } +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/com/sun/jdi/VisibleMethods.java Tue Oct 14 10:22:21 2014 -0700 @@ -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; + } +}
--- a/test/java/awt/Focus/SortingFPT/JDK8048887.java Wed Oct 08 14:15:17 2014 -0700 +++ b/test/java/awt/Focus/SortingFPT/JDK8048887.java Tue Oct 14 10:22:21 2014 -0700 @@ -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;
--- a/test/java/net/InetAddress/IPv4Formats.java Wed Oct 08 14:15:17 2014 -0700 +++ b/test/java/net/InetAddress/IPv4Formats.java Tue Oct 14 10:22:21 2014 -0700 @@ -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 } };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/java/util/logging/FileHandlerPath.java Tue Oct 14 10:22:21 2014 -0700 @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +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(); + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/xml/ws/xsanymixed/CopyingResponse.java Tue Oct 14 10:22:21 2014 -0700 @@ -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(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/xml/ws/xsanymixed/ServiceImpl.java Tue Oct 14 10:22:21 2014 -0700 @@ -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); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/xml/ws/xsanymixed/Test.java Tue Oct 14 10:22:21 2014 -0700 @@ -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(); + } + } + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/xml/ws/xsanymixed/compile-wsdl.sh Tue Oct 14 10:22:21 2014 -0700 @@ -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."
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/javax/xml/ws/xsanymixed/service.wsdl Tue Oct 14 10:22:21 2014 -0700 @@ -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>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/awt/datatransfer/DataFlavorComparatorTest1.java Tue Oct 14 10:22:21 2014 -0700 @@ -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); + } + } + } + } + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/sun/security/jgss/spnego/NotPreferredMech.java Tue Oct 14 10:22:21 2014 -0700 @@ -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"); + } + } +}
--- a/test/sun/text/resources/LocaleData Wed Oct 08 14:15:17 2014 -0700 +++ b/test/sun/text/resources/LocaleData Tue Oct 14 10:22:21 2014 -0700 @@ -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=
--- a/test/sun/text/resources/LocaleDataTest.java Wed Oct 08 14:15:17 2014 -0700 +++ b/test/sun/text/resources/LocaleDataTest.java Tue Oct 14 10:22:21 2014 -0700 @@ -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 * */