提交 5606a2cd 编写于 作者: J jcoomes

Merge

......@@ -1147,7 +1147,8 @@ JDWP "Java(tm) Debug Wire Protocol"
(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 @@ JDWP "Java(tm) Debug Wire Protocol"
)
)
(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 @@ JDWP "Java(tm) Debug Wire Protocol"
"<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 @@ JDWP "Java(tm) Debug Wire Protocol"
(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)
......
/*
* 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
};
/*
* 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[];
......@@ -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)
......
......@@ -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 @@ debugDispatch_initialize(void)
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;
......
......@@ -591,6 +591,8 @@ sharedInvoke(PacketInputStream *in, PacketOutputStream *out)
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 {
......
......@@ -37,6 +37,7 @@ import java.security.cert.CertificateException;
* @author Vincent Ryan
*/
@jdk.Exported
public abstract class ContentSigner {
/**
......
/*
* 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;
<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>
/*
* 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 @@ public class DriverResource_ja extends ListResourceBundle {
" -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",
......
......@@ -103,7 +103,7 @@ public interface ClassType extends ReferenceType {
* <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 @@ public interface ClassType extends ReferenceType {
* <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 @@ public interface ClassType extends ReferenceType {
* @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 @@ public interface ClassType extends ReferenceType {
* @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 @@ public interface ClassType extends ReferenceType {
* <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 @@ public interface ClassType extends ReferenceType {
* @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
......
......@@ -79,4 +79,123 @@ public interface InterfaceType extends ReferenceType {
* 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&trade; 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();
}
}
......@@ -137,6 +137,18 @@ public interface Method extends TypeComponent, Locatable, Comparable<Method> {
*/
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.
*
......
......@@ -194,10 +194,10 @@ public interface ObjectReference extends Value {
* {@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 @@ public interface ObjectReference extends Value {
* @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.
......
......@@ -42,13 +42,13 @@ FileChooser.renameError.textAndMnemonic={0}\u306E\u540D\u524D\u3092\u5909\u66F4\
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
......
......@@ -42,13 +42,13 @@ FileChooser.renameError.textAndMnemonic={0}\uC758 \uC774\uB984\uC744 \uBC14\uAFC
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
......
......@@ -42,13 +42,13 @@ FileChooser.renameError.textAndMnemonic=\u65E0\u6CD5\u91CD\u547D\u540D{0}
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
......
......@@ -42,13 +42,13 @@ FileChooser.renameError.textAndMnemonic=\u7121\u6CD5\u91CD\u65B0\u547D\u540D {0}
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
......
......@@ -559,6 +559,9 @@ abstract class LValue {
} 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());
......
......@@ -31,6 +31,7 @@ import java.util.List;
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 @@ public class ArrayTypeImpl extends ReferenceTypeImpl
return findType(componentSignature());
}
void addVisibleMethods(Map<String, Method> map) {
@Override
void addVisibleMethods(Map<String, Method> map, Set<InterfaceType> seenInterfaces) {
// arrays don't have methods
}
......
......@@ -29,9 +29,27 @@ import com.sun.jdi.*;
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 @@ public class ClassTypeImpl extends ReferenceTypeImpl
return superclass;
}
@Override
public List<InterfaceType> interfaces() {
if (interfaces == null) {
interfaces = getInterfaces();
......@@ -72,26 +91,9 @@ public class ClassTypeImpl extends ReferenceTypeImpl
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 @@ public class ClassTypeImpl extends ReferenceTypeImpl
}
}
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 @@ public class ClassTypeImpl extends ReferenceTypeImpl
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 @@ public class ClassTypeImpl extends ReferenceTypeImpl
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 @@ public class ClassTypeImpl extends ReferenceTypeImpl
}
}
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);
}
public String toString() {
return "class " + name() + " (" + loaderString() + ")";
}
addToMethodMap(methodMap, methods());
@Override
CommandSender getInvokeMethodSender(ThreadReferenceImpl thread,
MethodImpl method,
ValueImpl[] args,
int options) {
return () ->
JDWP.ClassType.InvokeMethod.enqueueCommand(vm,
ClassTypeImpl.this,
thread,
method.ref(),
args,
options);
}
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
InvocationResult waitForReply(PacketStream stream) throws JDWPException {
return new IResult(JDWP.ClassType.InvokeMethod.waitForReply(vm, stream));
}
public String toString() {
return "class " + name() + " (" + loaderString() + ")";
@Override
boolean canInvoke(Method method) {
// Method must be in this class or a superclass.
return ((ReferenceTypeImpl)method.declaringType()).isAssignableFrom(this);
}
}
......@@ -29,13 +29,31 @@ import com.sun.jdi.*;
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,103 +98,46 @@ public class InterfaceTypeImpl extends ReferenceTypeImpl
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 boolean isInitialized() {
return isPrepared();
}
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;
public String toString() {
return "interface " + name() + " (" + loaderString() + ")";
}
List<InterfaceType> allSuperinterfaces() {
ArrayList<InterfaceType> list = new ArrayList<InterfaceType>();
addSuperinterfaces(list);
return list;
@Override
InvocationResult waitForReply(PacketStream stream) throws JDWPException {
return new IResult(JDWP.InterfaceType.InvokeMethod.waitForReply(vm, stream));
}
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);
}
@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);
}
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;
}
@Override
ClassType superclass() {
return null;
}
List<InterfaceType> inheritedTypes() {
@Override
List<InterfaceType> interfaces() {
return superinterfaces();
}
public boolean isInitialized() {
return isPrepared();
}
public String toString() {
return "interface " + name() + " (" + loaderString() + ")";
@Override
boolean canInvoke(Method method) {
// method must be directly in this interface
return this.equals(method.declaringType());
}
}
}
\ No newline at end of file
/*
* 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);
}
......@@ -187,6 +187,13 @@ public abstract class MethodImpl extends TypeComponentImpl
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);
}
......
......@@ -277,7 +277,6 @@ public class ObjectReferenceImpl extends ValueImpl
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 @@ public class ObjectReferenceImpl extends ValueImpl
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 @@ public class ObjectReferenceImpl extends ValueImpl
* 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 @@ public class ObjectReferenceImpl extends ValueImpl
*/
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 @@ public class ObjectReferenceImpl extends ValueImpl
*/
}
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 @@ public class ObjectReferenceImpl extends ValueImpl
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 {
......
......@@ -511,7 +511,7 @@ implements ReferenceType {
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 @@ implements ReferenceType {
* 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
......
......@@ -48,7 +48,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManagerService {
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;
......
......@@ -62,7 +62,7 @@ class InvokerBytecodeGenerator {
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 @@ class InvokerBytecodeGenerator {
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;
......
......@@ -354,10 +354,11 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
* @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 @@ public class URLClassLoader extends SecureClassLoader implements Closeable {
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;
}
/*
......
/*
* 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 java.security.Provider.Service;
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 @@ import sun.security.jca.GetInstance.Instance;
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 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi {
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 @@ public abstract class KeyPairGenerator extends KeyPairGeneratorSpi {
provider = instance.provider;
this.serviceIterator = serviceIterator;
initType = I_NONE;
if (!skipDebug && pdebug != null) {
pdebug.println("KeyPairGenerator." + algorithm +
" algorithm from: " + provider.getName());
}
}
/**
......
......@@ -37,6 +37,8 @@ import javax.crypto.SecretKey;
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 @@ import javax.security.auth.callback.*;
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 @@ public class KeyStore {
this.keyStoreSpi = keyStoreSpi;
this.provider = provider;
this.type = type;
if (!skipDebug && pdebug != null) {
pdebug.println("KeyStore." + type.toUpperCase() + " type from: " +
this.provider.getName());
}
}
/**
......
......@@ -35,6 +35,8 @@ import java.io.ByteArrayInputStream;
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 @@ import java.nio.ByteBuffer;
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 abstract class MessageDigest extends MessageDigestSpi {
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");
}
......
......@@ -32,6 +32,7 @@ import java.security.Provider.Service;
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 @@ import sun.security.jca.GetInstance.Instance;
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 @@ public class SecureRandom extends java.util.Random {
this.secureRandomSpi = secureRandomSpi;
this.provider = provider;
this.algorithm = algorithm;
if (!skipDebug && pdebug != null) {
pdebug.println("SecureRandom." + algorithm +
" algorithm from: " + this.provider.getName());
}
}
/**
......
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -121,6 +121,11 @@ public abstract class Signature extends SignatureSpi {
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 @@ public abstract class Signature extends SignatureSpi {
throws InvalidKeyException {
engineInitVerify(publicKey);
state = VERIFY;
if (!skipDebug && pdebug != null) {
pdebug.println("Signature." + algorithm +
" verification algorithm from: " + this.provider.getName());
}
}
/**
......@@ -495,6 +505,11 @@ public abstract class Signature extends SignatureSpi {
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 @@ public abstract class Signature extends SignatureSpi {
throws InvalidKeyException {
engineInitSign(privateKey);
state = SIGN;
if (!skipDebug && pdebug != null) {
pdebug.println("Signature." + algorithm +
" signing algorithm from: " + this.provider.getName());
}
}
/**
......@@ -529,6 +549,11 @@ public abstract class Signature extends SignatureSpi {
throws InvalidKeyException {
engineInitSign(privateKey, random);
state = SIGN;
if (!skipDebug && pdebug != null) {
pdebug.println("Signature." + algorithm +
" signing algorithm from: " + this.provider.getName());
}
}
/**
......
......@@ -49,6 +49,7 @@ import java.util.concurrent.RejectedExecutionException;
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 @@ import java.security.Permissions;
*
* <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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
* (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.)
*
* 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.)
* 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. 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.
*
* Field "ctl" contains 64 bits holding all the information needed
* to atomically decide to add, inactivate, enqueue (on an event
* 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 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.
*
* 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.
* subfields.
*
* 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.
*
* 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"
* 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.
*
* 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.
*
* 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.
* 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 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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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.
*
* 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.
* 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.
*
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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).
*
* The order of declarations in this file is:
* 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 (with a few exceptions):
* (1) Static utility functions
* (2) Nested (static) classes
* (3) Static fields
......@@ -609,56 +746,37 @@ public class ForkJoinPool extends AbstractExecutorService {
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 @@ public class ForkJoinPool extends AbstractExecutorService {
*/
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,18 +811,22 @@ public class ForkJoinPool extends AbstractExecutorService {
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.
*/
......@@ -719,12 +841,10 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
*/
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 @@ public class ForkJoinPool extends AbstractExecutorService {
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 @@ public class ForkJoinPool extends AbstractExecutorService {
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 @@ public class ForkJoinPool extends AbstractExecutorService {
/**
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
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 @@ public class ForkJoinPool extends AbstractExecutorService {
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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
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 @@ public class ForkJoinPool extends AbstractExecutorService {
/**
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
}
/**
* Executes a top-level task and any local tasks remaining
* after execution.
* Removes and executes all local tasks. If LIFO, invokes
* pollAndExecAll. Otherwise implements a specialized pop loop
* to exec until empty.
*/
final void runTask(ForkJoinTask<?> task) {
if ((currentSteal = task) != null) {
ForkJoinWorkerThread thread;
task.doExec();
ForkJoinTask<?>[] a = array;
int md = mode;
++nsteals;
currentSteal = null;
if (md != 0)
pollAndExecAll();
else if (a != null) {
int s, m = a.length - 1;
ForkJoinTask<?> t;
while ((s = top - 1) - base >= 0 &&
(t = (ForkJoinTask<?>)U.getAndSetObject
(a, ((m & s) << ASHIFT) + ABASE, null)) != null) {
top = s;
final void execLocalTasks() {
int b = base, m, s;
ForkJoinTask<?>[] a = array;
if (b - (s = top - 1) <= 0 && a != null &&
(m = a.length - 1) >= 0) {
if ((config & FIFO_QUEUE) == 0) {
for (ForkJoinTask<?> t;;) {
if ((t = (ForkJoinTask<?>)U.getAndSetObject
(a, ((m & s) << ASHIFT) + ABASE, null)) == null)
break;
U.putOrderedInt(this, QTOP, s);
t.doExec();
if (base - (s = top - 1) > 0)
break;
}
}
if ((thread = owner) != null) // no need to do in finally clause
else
pollAndExecAll();
}
}
/**
* Executes the given task and any remaining local tasks.
*/
final void runTask(ForkJoinTask<?> task) {
if (task != null) {
scanState &= ~SCANNING; // mark as busy
(currentSteal = task).doExec();
U.putOrderedObject(this, QCURRENTSTEAL, null); // release for GC
execLocalTasks();
ForkJoinWorkerThread thread = owner;
if (++nsteals < 0) // collect on overflow
transferStealCount(pool);
scanState |= SCANNING;
if (thread != null)
thread.afterTopLevelExec();
}
}
/**
* 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.
*
* @return false if no progress can be made, else true
* Adds steal count to pool stealCounter if it exists, and resets.
*/
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;
}
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;
}
if (--n == 0) {
if (!empty && base == b)
stat = false;
break;
}
}
if (removed)
task.doExec();
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));
}
else
stat = false;
return stat;
}
/**
* Tries to poll for and execute the given task or any other
* task in its CountedCompleter computation.
* If present, removes from queue and executes the given task,
* or any other cancelled task. Used only by awaitJoin.
*
* @return true if queue empty and task not known to be done
*/
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();
final boolean tryRemoveAndExec(ForkJoinTask<?> task) {
ForkJoinTask<?>[] a; int m, s, b, n;
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;
}
}
return true;
else if (base == b) // replace with proxy
removed = U.compareAndSwapObject(
a, j, task, new EmptyTask());
if (removed)
task.doExec();
break;
}
else if ((r = r.completer) == null)
break; // not part of root computation
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 (task.status < 0)
return false;
}
}
return false;
return true;
}
/**
* Tries to pop 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 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 @@ public class ForkJoinPool extends AbstractExecutorService {
*/
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)
......@@ -1125,6 +1276,11 @@ public class ForkJoinPool extends AbstractExecutorService {
*/
static final int commonParallelism;
/**
* Limit on spare thread construction in tryCompensate.
*/
private static int commonMaxSpares;
/**
* Sequence number for creating workerNamePrefix.
*/
......@@ -1138,7 +1294,7 @@ public class ForkJoinPool extends AbstractExecutorService {
return ++poolNumberSequence;
}
// static constants
// static configuration constants
/**
* Initial timeout value (in nanoseconds) for the thread
......@@ -1148,27 +1304,32 @@ public class ForkJoinPool extends AbstractExecutorService {
* aggressive shrinkage during most transient stalls (long GCs
* etc).
*/
private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec
private static final long IDLE_TIMEOUT = 2000L * 1000L * 1000L; // 2sec
/**
* Timeout value when there are more threads than parallelism level
* Tolerance for idle timeouts, to cope with timer undershoots
*/
private static final long FAST_IDLE_TIMEOUT = 200L * 1000L * 1000L;
private static final long TIMEOUT_SLOP = 20L * 1000L * 1000L; // 20ms
/**
* Tolerance for idle timeouts, to cope with timer undershoots
* 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 long TIMEOUT_SLOP = 2000000L;
private static final int DEFAULT_COMMON_MAX_SPARES = 256;
/**
* 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.
* 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 MAX_HELP = 64;
private static final int SPINS = 1 << 11;
/**
* Increment for seed generators. See class ThreadLocal for
......@@ -1177,209 +1338,212 @@ public class ForkJoinPool extends AbstractExecutorService {
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)
*
* When convenient, we can extract the upper 32 bits of counts and
* the lower 32 bits of queue state, u = (int)(ctl >>> 32) and e =
* (int)ctl. The ec field is never accessed alone, but always
* together with id and st. The offsets of counts by the target
* parallelism and the positionings of fields makes it possible to
* perform the most common checks via sign tests of fields: When
* ac is negative, there are not enough active workers, when tc is
* negative, there are not enough total workers, and when e is
* negative, the pool is terminating. To deal with these possibly
* negative fields, we use casts in and out of "short" and/or
* signed shifts to maintain signedness.
*
* When a thread is queued (inactivated), its eventCount field is
* set negative, which is the only way to tell if a worker is
* prevented from executing tasks, even though it must continue to
* scan for them to avoid queuing races. Note however that
* eventCount updates lag releases so usage requires care.
*
* Field plock is an int packed with:
* SHUTDOWN: true if shutdown is enabled (1 bit)
* SEQ: a sequence lock, with PL_LOCK bit set if locked (30 bits)
* SIGNAL: set when threads may be waiting on the lock (1 bit)
*
* The sequence number enables simple consistency checks:
* Staleness of read-only operations on the workQueues array can
* be checked by comparing plock before vs after the reads.
*/
// bit positions/shifts for fields
* 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 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.
*
* 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.
*/
// Lower and upper word masks
private static final long SP_MASK = 0xffffffffL;
private static final long UC_MASK = ~SP_MASK;
// Active counts
private static final int AC_SHIFT = 48;
private static final long AC_UNIT = 0x0001L << AC_SHIFT;
private static final long AC_MASK = 0xffffL << AC_SHIFT;
// Total counts
private static final int TC_SHIFT = 32;
private static final int ST_SHIFT = 31;
private static final int EC_SHIFT = 16;
// bounds
private static final int SMASK = 0xffff; // short bits
private static final int MAX_CAP = 0x7fff; // max #workers - 1
private static final int EVENMASK = 0xfffe; // even short bits
private static final int SQMASK = 0x007e; // max 64 (even) slots
private static final int SHORT_SIGN = 1 << 15;
private static final int INT_SIGN = 1 << 31;
// masks
private static final long STOP_BIT = 0x0001L << ST_SHIFT;
private static final long AC_MASK = ((long)SMASK) << AC_SHIFT;
private static final long TC_MASK = ((long)SMASK) << TC_SHIFT;
// units for incrementing and decrementing
private static final long TC_UNIT = 1L << TC_SHIFT;
private static final long AC_UNIT = 1L << AC_SHIFT;
// masks and units for dealing with u = (int)(ctl >>> 32)
private static final int UAC_SHIFT = AC_SHIFT - 32;
private static final int UTC_SHIFT = TC_SHIFT - 32;
private static final int UAC_MASK = SMASK << UAC_SHIFT;
private static final int UTC_MASK = SMASK << UTC_SHIFT;
private static final int UAC_UNIT = 1 << UAC_SHIFT;
private static final int UTC_UNIT = 1 << UTC_SHIFT;
// masks and units for dealing with e = (int)ctl
private static final int E_MASK = 0x7fffffff; // no STOP_BIT
private static final int E_SEQ = 1 << EC_SHIFT;
// plock bits
private static final int SHUTDOWN = 1 << 31;
private static final int PL_LOCK = 2;
private static final int PL_SIGNAL = 1;
private static final int PL_SPINS = 1 << 8;
// access mode for WorkQueue
static final int LIFO_QUEUE = 0;
static final int FIFO_QUEUE = 1;
static final int SHARED_QUEUE = -1;
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
// runState bits: SHUTDOWN must be negative, others arbitrary powers of two
private static final int RSLOCK = 1;
private static final int RSIGNAL = 1 << 1;
private static final int STARTED = 1 << 2;
private static final int STOP = 1 << 29;
private static final int TERMINATED = 1 << 30;
private static final int SHUTDOWN = 1 << 31;
// Instance fields
volatile long stealCount; // collects worker counts
volatile long ctl; // main pool control
volatile int plock; // shutdown status and seqLock
volatile int indexSeed; // worker/submitter index seed
final short parallelism; // parallelism level
final short mode; // LIFO/FIFO
WorkQueue[] workQueues; // main registry
volatile long ctl; // main pool control
volatile int runState; // lockable status
final int config; // parallelism, mode
int indexSeed; // to generate worker index
volatile WorkQueue[] workQueues; // main registry
final ForkJoinWorkerThreadFactory factory;
final UncaughtExceptionHandler ueh; // per-worker UEH
final String workerNamePrefix; // to create worker name string
final UncaughtExceptionHandler ueh; // per-worker UEH
final String workerNamePrefix; // to create worker name string
volatile AtomicLong stealCounter; // also used as sync monitor
/**
* Acquires the plock lock to protect worker array and related
* updates. This method is called only if an initial CAS on plock
* fails. This acts as a spinlock for normal cases, but falls back
* to builtin monitor to block when (rarely) needed. This would be
* a terrible idea for a highly contended lock, but works fine as
* a more conservative alternative to a pure spinlock.
* Acquires the runState lock; returns current (locked) runState.
*/
private int acquirePlock() {
int spins = PL_SPINS, ps, nps;
for (;;) {
if (((ps = plock) & PL_LOCK) == 0 &&
U.compareAndSwapInt(this, PLOCK, ps, nps = ps + PL_LOCK))
return nps;
else if (spins >= 0) {
if (ThreadLocalRandom.nextSecondarySeed() >= 0)
private int lockRunState() {
int rs;
return ((((rs = runState) & RSLOCK) != 0 ||
!U.compareAndSwapInt(this, RUNSTATE, rs, rs |= RSLOCK)) ?
awaitRunStateLock() : rs);
}
/**
* Spins and/or blocks until runstate lock is available. See
* above for explanation.
*/
private int awaitRunStateLock() {
Object lock;
boolean wasInterrupted = false;
for (int spins = SPINS, r = 0, rs, ns;;) {
if (((rs = runState) & RSLOCK) == 0) {
if (U.compareAndSwapInt(this, RUNSTATE, rs, ns = rs | RSLOCK)) {
if (wasInterrupted) {
try {
Thread.currentThread().interrupt();
} catch (SecurityException ignore) {
}
}
return ns;
}
}
else if (r == 0)
r = ThreadLocalRandom.nextSecondarySeed();
else if (spins > 0) {
r ^= r << 6; r ^= r >>> 21; r ^= r << 7; // xorshift
if (r >= 0)
--spins;
}
else if (U.compareAndSwapInt(this, PLOCK, ps, ps | PL_SIGNAL)) {
synchronized (this) {
if ((plock & PL_SIGNAL) != 0) {
else if ((rs & STARTED) == 0 || (lock = stealCounter) == null)
Thread.yield(); // initialization race
else if (U.compareAndSwapInt(this, RUNSTATE, rs, rs | RSIGNAL)) {
synchronized (lock) {
if ((runState & RSIGNAL) != 0) {
try {
wait();
lock.wait();
} catch (InterruptedException ie) {
try {
Thread.currentThread().interrupt();
} catch (SecurityException ignore) {
}
if (!(Thread.currentThread() instanceof
ForkJoinWorkerThread))
wasInterrupted = true;
}
}
else
notifyAll();
lock.notifyAll();
}
}
}
}
/**
* Unlocks and signals any thread waiting for plock. Called only
* when CAS of seq value for unlock fails.
* Unlocks and sets runState to newRunState.
*
* @param oldRunState a value returned from lockRunState
* @param newRunState the next value (must have lock bit clear).
*/
private void releasePlock(int ps) {
plock = ps;
synchronized (this) { notifyAll(); }
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 create and start one worker if fewer than target
* parallelism level exist. Adjusts counts etc on failure.
* 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 void tryAddWorker() {
long c; int u, e;
while ((u = (int)((c = ctl) >>> 32)) < 0 &&
(u & SHORT_SIGN) != 0 && (e = (int)c) >= 0) {
long nc = ((long)(((u + UTC_UNIT) & UTC_MASK) |
((u + UAC_UNIT) & UAC_MASK)) << 32) | (long)e;
if (U.compareAndSwapLong(this, CTL, c, nc)) {
ForkJoinWorkerThreadFactory fac;
Throwable ex = null;
ForkJoinWorkerThread wt = null;
try {
if ((fac = factory) != null &&
(wt = fac.newThread(this)) != null) {
wt.start();
break;
}
} catch (Throwable rex) {
ex = rex;
}
deregisterWorker(wt, ex);
break;
private 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;
}
// Registering and deregistering workers
/**
* Tries to add one worker, incrementing ctl counts before doing
* so, relying on createWorker to back out on failure.
*
* @param c incoming ctl value, with total count negative and no
* idle workers. On CAS failure, c is refreshed and retried if
* this holds (otherwise, a new worker is not needed).
*/
private void tryAddWorker(long c) {
boolean add = false;
do {
long nc = ((AC_MASK & (c + AC_UNIT)) |
(TC_MASK & (c + TC_UNIT)));
if (ctl == c) {
int rs, stop; // check if terminating
if ((stop = (rs = lockRunState()) & STOP) == 0)
add = U.compareAndSwapLong(this, CTL, c, nc);
unlockRunState(rs, rs & ~RSLOCK);
if (stop != 0)
break;
if (add) {
createWorker();
break;
}
}
} while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
}
/**
* Callback from ForkJoinWorkerThread 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 @@ public class ForkJoinPool extends AbstractExecutorService {
}
}
}
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 @@ public class ForkJoinPool extends AbstractExecutorService {
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);
}
}
long c; // adjust ctl counts
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; // 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;
long nc = (((long)(w.nextWait & E_MASK)) |
((long)(u + UAC_UNIT)) << 32);
int ne = (e + E_SEQ) & E_MASK;
if (w.eventCount == (e | INT_SIGN) &&
U.compareAndSwapLong(this, CTL, c, nc)) {
w.eventCount = ne;
if ((p = w.parker) != null)
if ((v = ws[i]) == null) // terminating
break;
int vs = (sp + SS_SEQ) & ~INACTIVE; // next scanState
int d = sp - v.scanState; // screen CAS
long nc = (UC_MASK & (c + AC_UNIT)) | (SP_MASK & v.stackPred);
if (d == 0 && U.compareAndSwapLong(this, CTL, c, nc)) {
v.scanState = vs; // activate v
if ((p = v.parker) != null)
U.unpark(p);
break;
}
if (q != null && q.base >= q.top)
if (q != null && q.base == q.top) // no more work
break;
}
}
/**
* Signals and releases worker v if it is top of idle worker
* stack. This performs a one-shot version of signalWork only if
* there is (apparently) at least one idle worker.
*
* @param c incoming ctl value
* @param v if non-null, a worker
* @param inc the increment to active count (zero when compensating)
* @return true if successful
*/
private boolean tryRelease(long c, WorkQueue v, long inc) {
int sp = (int)c, vs = (sp + SS_SEQ) & ~INACTIVE; Thread p;
if (v != null && v.scanState == sp) { // v is at top of stack
long nc = (UC_MASK & (c + inc)) | (SP_MASK & v.stackPred);
if (U.compareAndSwapLong(this, CTL, c, nc)) {
v.scanState = vs;
if ((p = v.parker) != null)
U.unpark(p);
return true;
}
}
return false;
}
// Scanning for tasks
/**
* Top-level runloop for workers, called by ForkJoinWorkerThread.run.
*/
final void runWorker(WorkQueue w) {
w.growArray(); // allocate queue
for (int r = w.hint; scan(w, r) == 0; ) {
w.growArray(); // allocate queue
int seed = w.hint; // initially holds randomization hint
int r = (seed == 0) ? 1 : seed; // avoid 0 for xorShift
for (ForkJoinTask<?> t;;) {
if ((t = scan(w, r)) != null)
w.runTask(t);
else if (!awaitWork(w, r))
break;
r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
}
}
/**
* Scans for and, if found, runs one task, else possibly
* inactivates the worker. This method operates on single reads of
* volatile state and is designed to be re-invoked continuously,
* in part because it returns upon detecting inconsistencies,
* contention, or state changes that indicate possible success on
* re-invocation.
*
* The scan searches for tasks across queues starting at a random
* index, checking each at least twice. The scan terminates upon
* either finding a non-empty queue, or completing the sweep. If
* the worker is not inactivated, it takes and runs a task from
* this queue. Otherwise, if not activated, it tries to activate
* itself or some other worker by signalling. On failure to find a
* task, returns (for retry) if pool state may have changed during
* an empty scan, or tries to inactivate if active, else possibly
* blocks or terminates via method awaitWork.
* Scans for and tries to steal a top-level task. Scans start at a
* random location, randomly moving on apparent contention,
* otherwise continuing linearly until reaching two consecutive
* empty passes over all queues with the same checksum (summing
* each base index of each queue, that moves on each steal), at
* which point the worker tries to inactivate and then re-scans,
* attempting to re-activate (itself or some other worker) if
* finding a task; otherwise returning null to await work. Scans
* otherwise touch as little memory as possible, to reduce
* disruption on other scanning threads.
*
* @param w the worker (via its WorkQueue)
* @param r a random seed
* @return worker qlock status if would have waited, else 0
* @return a task, or null if none found
*/
private final int scan(WorkQueue w, int r) {
private ForkJoinTask<?> scan(WorkQueue w, int r) {
WorkQueue[] ws; int m;
long c = ctl; // for consistency check
if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 && w != null) {
for (int j = m + m + 1, ec = w.eventCount;;) {
WorkQueue q; int b, e; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
if ((q = ws[(r - j) & m]) != null &&
(b = q.base) - q.top < 0 && (a = q.array) != null) {
long i = (((a.length - 1) & b) << ASHIFT) + ABASE;
if ((t = ((ForkJoinTask<?>)
U.getObjectVolatile(a, i))) != null) {
if (ec < 0)
helpRelease(c, ws, w, q, b);
else if (q.base == b &&
U.compareAndSwapObject(a, i, t, null)) {
U.putOrderedInt(q, QBASE, b + 1);
if ((b + 1) - q.top < 0)
signalWork(ws, q);
w.runTask(t);
if ((ws = workQueues) != null && (m = ws.length - 1) > 0 && w != null) {
int ss = w.scanState; // initially non-negative
for (int origin = r & m, k = origin, oldSum = 0, checkSum = 0;;) {
WorkQueue q; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
int b, n; long c;
if ((q = ws[k]) != null) {
if ((n = (b = q.base) - q.top) < 0 &&
(a = q.array) != null) { // non-empty
long i = (((a.length - 1) & b) << ASHIFT) + ABASE;
if ((t = ((ForkJoinTask<?>)
U.getObjectVolatile(a, i))) != null &&
q.base == b) {
if (ss >= 0) {
if (U.compareAndSwapObject(a, i, t, null)) {
q.base = b + 1;
if (n < -1) // signal others
signalWork(ws, q);
return t;
}
}
else if (oldSum == 0 && // try to activate
w.scanState < 0)
tryRelease(c = ctl, ws[m & (int)c], AC_UNIT);
}
if (ss < 0) // refresh
ss = w.scanState;
r ^= r << 1; r ^= r >>> 3; r ^= r << 10;
origin = k = r & m; // move and rescan
oldSum = checkSum = 0;
continue;
}
break;
checkSum += b;
}
else if (--j < 0) {
if ((ec | (e = (int)c)) < 0) // inactive or terminating
return awaitWork(w, c, ec);
else if (ctl == c) { // try to inactivate and enqueue
long nc = (long)ec | ((c - AC_UNIT) & (AC_MASK|TC_MASK));
w.nextWait = e;
w.eventCount = ec | INT_SIGN;
if (!U.compareAndSwapLong(this, CTL, c, nc))
w.eventCount = ec; // back out
if ((k = (k + 1) & m) == origin) { // continue until stable
if ((ss >= 0 || (ss == (ss = w.scanState))) &&
oldSum == (oldSum = checkSum)) {
if (ss < 0 || w.qlock < 0) // already inactive
break;
int ns = ss | INACTIVE; // try to inactivate
long nc = ((SP_MASK & ns) |
(UC_MASK & ((c = ctl) - AC_UNIT)));
w.stackPred = (int)c; // hold prev stack top
U.putInt(w, QSCANSTATE, ns);
if (U.compareAndSwapLong(this, CTL, c, nc))
ss = ns;
else
w.scanState = ss; // back out
}
break;
checkSum = 0;
}
}
}
return 0;
return null;
}
/**
* A continuation of scan(), possibly blocking or terminating
* worker w. Returns without blocking if pool state has apparently
* changed since last invocation. Also, if inactivating w has
* caused the pool to become quiescent, checks for pool
* Possibly blocks worker w waiting for a task to steal, or
* returns false if the worker should terminate. If inactivating
* w has caused the pool to become quiescent, checks for pool
* termination, and, so long as this is not the only worker, waits
* for event for up to a given duration. On timeout, if ctl has
* not changed, terminates the worker, which will in turn wake up
* for up to a given duration. On timeout, if ctl has not
* changed, terminates the worker, which will in turn wake up
* another worker to possibly repeat this process.
*
* @param w the calling worker
* @param c the ctl value on entry to scan
* @param ec the worker's eventCount on entry to scan
*/
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);
* @param r a random seed (for spins)
* @return false if the worker should terminate
*/
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 stat;
return true;
}
// Joining tasks
/**
* 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.
* 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
*/
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);
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 s;
}
/**
......@@ -1799,268 +1901,167 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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.
*
* @param c the assumed ctl value
*/
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
* for blocking. Returns false (retryable by caller), on
* contention, detected staleness, instability, or termination.
*
* @param w caller
*/
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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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) {
U.putOrderedObject(w, QCURRENTSTEAL, t);
t.doExec();
if (++w.nsteals < 0)
w.transferStealCount(this);
}
if ((b = q.base) - q.top < 0 && (t = q.pollAt(b)) != null)
w.runTask(t);
}
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 @@ public class ForkJoinPool extends AbstractExecutorService {
/**
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
// 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 @@ public class ForkJoinPool extends AbstractExecutorService {
* @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);
}
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
rs = lockRunState(); // enter SHUTDOWN phase
unlockRunState(rs, (rs & ~RSLOCK) | SHUTDOWN);
}
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;
}
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 ((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;
}
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);
}
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) {
}
}
if (w.scanState < 0)
U.unpark(wt); // wake up
}
// 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 (checkSum != oldSum) { // unstable
oldSum = checkSum;
pass = 0;
}
else if (pass > 3 && pass > m) // can't further help
break;
else if (++pass > 1) { // try to dequeue
long c; int j = 0, sp; // bound attempts
while (j++ <= m && (sp = (int)(c = ctl)) != 0)
tryRelease(c, ws[sp & m], AC_UNIT);
}
}
return true;
}
// External operations
/**
* Full version of externalPush, handling uncommon cases, as well
* as performing secondary initialization upon the first
* submission of the first task to the pool. It also detects
* first submission by an external thread and creates a new shared
* queue if the one at index if empty or contended.
*
* @param task the task. Caller must ensure non-null.
*/
private void externalSubmit(ForkJoinTask<?> task) {
int r; // initialize caller's probe
if ((r = ThreadLocalRandom.getProbe()) == 0) {
ThreadLocalRandom.localInit();
r = ThreadLocalRandom.getProbe();
}
for (;;) {
WorkQueue[] ws; WorkQueue q; int rs, m, k;
boolean move = false;
if ((rs = runState) < 0) {
tryTerminate(false, false); // help terminate
throw new RejectedExecutionException();
}
else if ((rs & STARTED) == 0 || // initialize
((ws = workQueues) == null || (m = ws.length - 1) < 0)) {
int ns = 0;
rs = lockRunState();
try {
if ((rs & STARTED) == 0) {
U.compareAndSwapObject(this, STEALCOUNTER, null,
new AtomicLong());
// create workQueues array with size a power of two
int p = config & SMASK; // ensure at least 2 slots
int n = (p > 1) ? p - 1 : 1;
n |= n >>> 1; n |= n >>> 2; n |= n >>> 4;
n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1;
workQueues = new WorkQueue[n];
ns = STARTED;
}
} finally {
unlockRunState(rs, (rs & ~RSLOCK) | ns);
}
}
else if ((q = ws[k = r & m & SQMASK]) != null) {
if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) {
ForkJoinTask<?>[] a = q.array;
int s = q.top;
boolean submitted = false; // initial submission or resizing
try { // locked version of push
if ((a != null && a.length > s + 1 - q.base) ||
(a = q.growArray()) != null) {
int j = (((a.length - 1) & s) << ASHIFT) + ABASE;
U.putOrderedObject(a, j, task);
U.putOrderedInt(q, QTOP, s + 1);
submitted = true;
}
} finally {
U.compareAndSwapInt(q, QLOCK, 1, 0);
}
if (submitted) {
signalWork(ws, q);
return;
}
}
move = true; // move on failure
}
else if (((rs = runState) & RSLOCK) == 0) { // create new queue
q = new WorkQueue(this, null);
q.hint = r;
q.config = k | SHARED_QUEUE;
q.scanState = INACTIVE;
rs = lockRunState(); // publish index
if (rs > 0 && (ws = workQueues) != null &&
k < ws.length && ws[k] == null)
ws[k] = q; // else terminated
unlockRunState(rs, rs & ~RSLOCK);
}
else
move = true; // move if busy
if (move)
r = ThreadLocalRandom.advanceProbe(r);
}
}
// external operations on common pool
/**
* Tries to add the given task to a submission queue at
* submitter's current queue. Only the (vastly) most common path
* is directly handled in this method, while screening for need
* for externalSubmit.
*
* @param task the task. Caller must ensure non-null.
*/
final void externalPush(ForkJoinTask<?> task) {
WorkQueue[] ws; WorkQueue q; int m;
int r = ThreadLocalRandom.getProbe();
int rs = runState;
if ((ws = workQueues) != null && (m = (ws.length - 1)) >= 0 &&
(q = ws[m & r & SQMASK]) != null && r != 0 && rs > 0 &&
U.compareAndSwapInt(q, QLOCK, 0, 1)) {
ForkJoinTask<?>[] a; int am, n, s;
if ((a = q.array) != null &&
(am = a.length - 1) > (n = (s = q.top) - q.base)) {
int j = ((am & s) << ASHIFT) + ABASE;
U.putOrderedObject(a, j, task);
U.putOrderedInt(q, QTOP, s + 1);
U.putOrderedInt(q, QLOCK, 0);
if (n <= 1)
signalWork(ws, q);
return;
}
U.compareAndSwapInt(q, QLOCK, 1, 0);
}
externalSubmit(task);
}
/**
* Returns common pool queue for a thread that has submitted at
* least one task.
* Returns common pool queue for an external thread.
*/
static WorkQueue commonSubmitterQueue() {
ForkJoinPool p; WorkQueue[] ws; int m, z;
return ((z = ThreadLocalRandom.getProbe()) != 0 &&
(p = common) != null &&
(ws = p.workQueues) != null &&
ForkJoinPool p = common;
int r = ThreadLocalRandom.getProbe();
WorkQueue[] ws; int m;
return (p != null && (ws = p.workQueues) != null &&
(m = ws.length - 1) >= 0) ?
ws[m & z & SQMASK] : null;
ws[m & r & SQMASK] : null;
}
/**
* Tries to pop the given task from submitter's queue in common pool.
* Performs tryUnpush for an external submitter: Finds queue,
* locks if apparently non-empty, validates upon locking, and
* adjusts top. Each check can fail but rarely does.
*/
final boolean tryExternalUnpush(ForkJoinTask<?> task) {
WorkQueue joiner; ForkJoinTask<?>[] a; int m, s;
WorkQueue[] ws = workQueues;
int z = ThreadLocalRandom.getProbe();
boolean popped = false;
if (ws != null && (m = ws.length - 1) >= 0 &&
(joiner = ws[z & m & SQMASK]) != null &&
joiner.base != (s = joiner.top) &&
(a = joiner.array) != null) {
WorkQueue[] ws; WorkQueue w; ForkJoinTask<?>[] a; int m, s;
int r = ThreadLocalRandom.getProbe();
if ((ws = workQueues) != null && (m = ws.length - 1) >= 0 &&
(w = ws[m & r & SQMASK]) != null &&
(a = w.array) != null && (s = w.top) != w.base) {
long j = (((a.length - 1) & (s - 1)) << ASHIFT) + ABASE;
if (U.getObject(a, j) == task &&
U.compareAndSwapInt(joiner, QLOCK, 0, 1)) {
if (joiner.top == s && joiner.array == a &&
if (U.compareAndSwapInt(w, QLOCK, 0, 1)) {
if (w.top == s && w.array == a &&
U.getObject(a, j) == task &&
U.compareAndSwapObject(a, j, task, null)) {
joiner.top = s - 1;
popped = true;
U.putOrderedInt(w, QTOP, s - 1);
U.putOrderedInt(w, QLOCK, 0);
return true;
}
joiner.qlock = 0;
U.compareAndSwapInt(w, QLOCK, 1, 0);
}
}
return popped;
return false;
}
/**
* Performs helpComplete for an external submitter.
*/
final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
WorkQueue joiner; int m;
WorkQueue[] ws = workQueues;
int j = ThreadLocalRandom.getProbe();
int s = 0;
if (ws != null && (m = ws.length - 1) >= 0 &&
(joiner = ws[j & m & SQMASK]) != null && task != null) {
int scans = m + m + 1;
long c = 0L; // for stability check
j |= 1; // poll odd queues
for (int k = scans; ; j += 2) {
WorkQueue q;
if ((s = task.status) < 0)
break;
else if (joiner.externalPopAndExecCC(task)) {
if (--maxTasks <= 0) {
s = task.status;
break;
}
k = scans;
}
else if ((s = task.status) < 0)
break;
else if ((q = ws[j & m]) != null && q.pollAndExecCC(task)) {
if (--maxTasks <= 0) {
s = task.status;
break;
}
k = scans;
}
else if (--k < 0) {
if (c == (c = ctl))
break;
k = scans;
}
}
}
return s;
WorkQueue[] ws; int n;
int r = ThreadLocalRandom.getProbe();
return ((ws = workQueues) == null || (n = ws.length) == 0) ? 0 :
helpComplete(ws[(n - 1) & r & SQMASK], task, maxTasks);
}
// Exported methods
......@@ -2447,7 +2533,7 @@ public class ForkJoinPool extends AbstractExecutorService {
this(checkParallelism(parallelism),
checkFactory(factory),
handler,
(asyncMode ? FIFO_QUEUE : LIFO_QUEUE),
asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
"ForkJoinPool-" + nextPoolId() + "-worker-");
checkPermission();
}
......@@ -2478,8 +2564,7 @@ public class ForkJoinPool extends AbstractExecutorService {
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 @@ public class ForkJoinPool extends AbstractExecutorService {
// 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 class ForkJoinPool extends AbstractExecutorService {
*/
public int getParallelism() {
int par;
return ((par = parallelism) > 0) ? par : 1;
return ((par = config & SMASK) > 0) ? par : 1;
}
/**
......@@ -2692,7 +2777,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @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 @@ public class ForkJoinPool extends AbstractExecutorService {
* @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 @@ public class ForkJoinPool extends AbstractExecutorService {
* @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 @@ public class ForkJoinPool extends AbstractExecutorService {
* @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 @@ public class ForkJoinPool extends AbstractExecutorService {
* @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 class ForkJoinPool extends AbstractExecutorService {
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 @@ public class ForkJoinPool extends AbstractExecutorService {
}
}
}
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 @@ public class ForkJoinPool extends AbstractExecutorService {
* @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 @@ public class ForkJoinPool extends AbstractExecutorService {
* @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 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return {@code true} if this pool has been shut down
*/
public boolean isShutdown() {
return plock < 0;
return (runState & SHUTDOWN) != 0;
}
/**
......@@ -3090,8 +3174,9 @@ public class ForkJoinPool extends AbstractExecutorService {
}
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 @@ public class ForkJoinPool extends AbstractExecutorService {
* 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 @@ public class ForkJoinPool extends AbstractExecutorService {
}
/**
* 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>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 the caller is not a {@link ForkJoinTask}, this method is
* <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 @@ public class ForkJoinPool extends AbstractExecutorService {
// 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 @@ public class ForkJoinPool extends AbstractExecutorService {
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 @@ public class ForkJoinPool extends AbstractExecutorService {
throw new Error(e);
}
commonMaxSpares = DEFAULT_COMMON_MAX_SPARES;
defaultForkJoinWorkerThreadFactory =
new DefaultForkJoinWorkerThreadFactory();
modifyThreadPermission = new RuntimePermission("modifyThread");
......@@ -3289,7 +3393,7 @@ public class ForkJoinPool extends AbstractExecutorService {
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;
}
......
......@@ -297,15 +297,22 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
}
/**
* 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 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* @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 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
*/
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 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
((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 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
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 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
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 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
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 abstract class ForkJoinTask<V> implements Future<V>, Serializable {
*/
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)
......
......@@ -66,7 +66,7 @@ public class ForkJoinWorkerThread extends Thread {
* 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 @@ public class ForkJoinWorkerThread extends Thread {
* @return the index number
*/
public int getPoolIndex() {
return workQueue.poolIndex >>> 1; // ignore odd/even tag bit
return workQueue.getPoolIndex();
}
/**
......@@ -171,7 +171,7 @@ public class ForkJoinWorkerThread extends Thread {
}
/**
* 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 @@ public class ForkJoinWorkerThread extends Thread {
/**
* 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 @@ public class ForkJoinWorkerThread extends Thread {
}
}
......@@ -402,6 +402,14 @@ public class FileHandler extends StreamHandler {
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 @@ public class FileHandler extends StreamHandler {
// 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);
......
/*
* 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 @@ public class Cipher {
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 @@ public class Cipher {
}
}
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 @@ public class Cipher {
initialized = true;
this.opmode = opmode;
if (!skipDebug && pdebug != null) {
pdebug.println("Cipher." + transformation + " " +
getOpmodeString(opmode) + " algorithm from: " +
this.provider.getName());
}
}
/**
......@@ -1372,6 +1398,12 @@ public class Cipher {
initialized = true;
this.opmode = opmode;
if (!skipDebug && pdebug != null) {
pdebug.println("Cipher." + transformation + " " +
getOpmodeString(opmode) + " algorithm from: " +
this.provider.getName());
}
}
/**
......@@ -1509,6 +1541,12 @@ public class Cipher {
initialized = true;
this.opmode = opmode;
if (!skipDebug && pdebug != null) {
pdebug.println("Cipher." + transformation + " " +
getOpmodeString(opmode) + " algorithm from: " +
this.provider.getName());
}
}
/**
......@@ -1693,6 +1731,12 @@ public class Cipher {
initialized = true;
this.opmode = opmode;
if (!skipDebug && pdebug != null) {
pdebug.println("Cipher." + transformation + " " +
getOpmodeString(opmode) + " algorithm from: " +
this.provider.getName());
}
}
/**
......
/*
* 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 @@ public class KeyAgreement {
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 @@ public class KeyAgreement {
throw new InvalidKeyException(e);
}
}
if (!skipDebug && pdebug != null) {
pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
this.provider.getName());
}
}
/**
......@@ -524,6 +534,11 @@ public class KeyAgreement {
} else {
chooseProvider(I_PARAMS, key, params, random);
}
if (!skipDebug && pdebug != null) {
pdebug.println("KeyAgreement." + algorithm + " algorithm from: " +
this.provider.getName());
}
}
/**
......
/*
* 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 java.security.spec.*;
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 @@ import sun.security.jca.GetInstance.Instance;
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 @@ public class KeyGenerator {
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 @@ public class KeyGenerator {
throw new NoSuchAlgorithmException
(algorithm + " KeyGenerator not available");
}
if (!skipDebug && pdebug != null) {
pdebug.println("KeyGenerator." + algorithm + " algorithm from: " +
this.provider.getName());
}
}
/**
......
/*
* 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 @@ public class Mac implements Cloneable {
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 @@ public class Mac implements Cloneable {
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 @@ public class Mac implements Cloneable {
chooseProvider(key, params);
}
initialized = true;
if (!skipDebug && pdebug != null) {
pdebug.println("Mac." + algorithm + " algorithm from: " +
this.provider.getName());
}
}
/**
......
......@@ -2895,6 +2895,14 @@ search:
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.
......
......@@ -523,13 +523,6 @@ public class SpNegoContext implements GSSContextSpi {
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 @@ public class SpNegoContext implements GSSContextSpi {
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 @@ public class SpNegoContext implements GSSContextSpi {
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 @@ public class SpNegoContext implements GSSContextSpi {
* 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)
......
......@@ -336,7 +336,7 @@ public class Resources extends java.util.ListResourceBundle {
{"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: "},
......
......@@ -336,7 +336,7 @@ public class Resources_de extends java.util.ListResourceBundle {
{"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: "},
......
/*
* 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 @@ public class Resources_es extends java.util.ListResourceBundle {
{"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}: "},
......
/*
* 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 @@ public class Resources_fr extends java.util.ListResourceBundle {
{"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} : "},
......
/*
* 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 @@ public class Resources_it extends java.util.ListResourceBundle {
{"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}: "},
......
......@@ -248,7 +248,7 @@ public class Resources_ja extends java.util.ListResourceBundle {
"\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 @@ public class Resources_ja extends java.util.ListResourceBundle {
{"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: "},
......
/*
* 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 @@ public class Resources_ko extends java.util.ListResourceBundle {
{"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: "},
......
......@@ -336,7 +336,7 @@ public class Resources_pt_BR extends java.util.ListResourceBundle {
{"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}: "},
......
/*
* 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 @@ public class Resources_sv extends java.util.ListResourceBundle {
{"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}: "},
......
/*
* 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 @@ public class Resources_zh_CN extends java.util.ListResourceBundle {
{"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: "},
......
/*
* 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 @@ public class Resources_zh_TW extends java.util.ListResourceBundle {
{"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: "},
......
/*
* 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 @@ public class Debug {
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);
......
/*
* 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 @@ public class FormatData extends ParallelListResourceBundle {
},
{ "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",
"",
}
},
......
/*
* 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 @@ public class FormatData_en extends ParallelListResourceBundle {
// 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
......
......@@ -103,7 +103,7 @@ HELP_ABOUT_DIALOG_JCONSOLE_VERSION=JConsole\u30D0\u30FC\u30B8\u30E7\u30F3:<br>{0
HELP_ABOUT_DIALOG_JAVA_VERSION=Java VM\u30D0\u30FC\u30B8\u30E7\u30F3:<br>{0}
HELP_ABOUT_DIALOG_MASTHEAD_ACCESSIBLE_NAME=\u30DE\u30B9\u30C8\u30D8\u30C3\u30C9\u56F3\u5F62
HELP_ABOUT_DIALOG_MASTHEAD_TITLE=JConsole\u306B\u3064\u3044\u3066
HELP_ABOUT_DIALOG_TITLE=JConsole: \u8A73\u7D30
HELP_ABOUT_DIALOG_TITLE=JConsole: \u60C5\u5831
HELP_ABOUT_DIALOG_USER_GUIDE_LINK_URL=http://docs.oracle.com/javase/{0}/docs/technotes/guides/management/jconsole.html
HELP_MENU_ABOUT_TITLE=JConsole\u306B\u3064\u3044\u3066(&A)
HELP_MENU_USER_GUIDE_TITLE=\u30AA\u30F3\u30E9\u30A4\u30F3\u30FB\u30E6\u30FC\u30B6\u30FC\u30FB\u30AC\u30A4\u30C9(&U)
......
......@@ -41,7 +41,9 @@ extern "C" {
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 @@ jbyteArray getEncodedBytes(JNIEnv *env, SECItem *hSECItem)
return jEncodedBytes;
}
/*
* Class: sun_security_ec_ECKeyPairGenerator
* Method: generateECKeyPair
......@@ -103,6 +104,9 @@ JNICALL Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair
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(&params_item, &ecparams, 0) != SECSuccess) {
......@@ -170,6 +174,7 @@ cleanup:
SECITEM_FreeItem(&privKey->publicValue, B_FALSE);
free(privKey);
}
if (pSeedBuffer) {
delete [] pSeedBuffer;
}
......@@ -206,6 +211,7 @@ JNICALL Java_sun_security_ec_ECDSASignature_signDigest
digest_item.len = jDigestLength;
ECPrivateKey privKey;
privKey.privateValue.data = NULL;
// Initialize the ECParams struct
ECParams *ecparams = NULL;
......@@ -213,6 +219,9 @@ JNICALL Java_sun_security_ec_ECDSASignature_signDigest
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(&params_item, &ecparams, 0) != SECSuccess) {
......@@ -226,6 +235,9 @@ JNICALL Java_sun_security_ec_ECDSASignature_signDigest
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 @@ JNICALL Java_sun_security_ec_ECDSASignature_signDigest
// 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 @@ JNICALL Java_sun_security_ec_ECDSASignature_verifySignedDigest
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(&params_item, &ecparams, 0) != SECSuccess) {
......@@ -369,25 +387,37 @@ JNICALL Java_sun_security_ec_ECDHKeyAgreement_deriveKey
(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(&params_item, &ecparams, 0) != SECSuccess) {
......@@ -409,6 +439,9 @@ JNICALL Java_sun_security_ec_ECDHKeyAgreement_deriveKey
// 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,
......
/*
* 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 @@ class XRootWindow extends XBaseWindow {
}
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){
......
......@@ -2354,9 +2354,7 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
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 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
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 @@ public final class XToolkit extends UNIXToolkit implements Runnable {
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");
......
......@@ -52,6 +52,8 @@
*/
extern XErrorHandler current_native_xerror_handler;
Window get_xawt_root_shell(JNIEnv *env);
#endif /* !HEADLESS */
#ifndef INTERSECTS
......
......@@ -2011,10 +2011,14 @@ static Bool exitSecondaryLoop = True;
* 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 @@ Java_sun_awt_X11_XlibWrapper_XNextSecondaryLoopEvent(JNIEnv *env, jclass clazz,
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;
......
......@@ -670,7 +670,7 @@ Java_sun_java2d_windows_GDIRenderer_doFillPoly
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);
}
......
/*
* 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 @@ ALG_ID MapHashAlgorithm(JNIEnv *env, jstring jHashAlgorithm) {
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 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_PRNG_generateSeed
*/
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 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_PRNG_generateSeed
} 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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_loadKeysOrCertificateCh
__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 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_RSAKeyPairGenerator_generateR
__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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_storeCertificate
__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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_removeCertificate
__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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_removeCertificate
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 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_KeyStore_destroyKeyContainer
__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 @@ JNIEXPORT jlong JNICALL Java_sun_security_mscapi_RSACipher_findCertificateUsingA
__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 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSAPublicKey_getExponent
__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 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_RSAPublicKey_getModulus
__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 @@ int convertToLittleEndian(JNIEnv *env, jbyteArray source, jbyte* destination,
}
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 @@ jbyteArray generateKeyBlob(
}
// 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 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_KeyStore_storePrivateKey
__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 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_RSASignature_importPublicKey
__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
......
......@@ -3955,7 +3955,6 @@ void AwtComponent::SendInputMethodEvent(jint id, jstring text,
DASSERT(stringCls);
CHECK_NULL(stringCls);
clauseReading = env->NewObjectArray(cClause, stringCls, NULL);
env->DeleteLocalRef(stringCls);
DASSERT(clauseReading);
CHECK_NULL(clauseReading);
for (int i=0; i<cClause; i++) env->SetObjectArrayElement(clauseReading, i, rgClauseReading[i]);
......
......@@ -47,16 +47,12 @@ struct ReplaceTextStruct {
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 @@ AwtTextArea::~AwtTextArea()
void AwtTextArea::Dispose()
{
if (m_hEditCtrl != NULL) {
VERIFY(::DestroyWindow(m_hEditCtrl));
m_hEditCtrl = NULL;
}
AwtTextComponent::Dispose();
}
......@@ -91,10 +83,6 @@ void AwtTextArea::EditSetSel(CHARRANGE &cr) {
}
}
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 @@ AwtTextArea::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
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)
{
......@@ -313,28 +148,9 @@ AwtTextArea::WmNcHitTest(UINT x, UINT y, LRESULT& retVal)
}
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 @@ AwtTextArea::HandleEvent(MSG *msg, BOOL synthetic)
}
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 @@ AwtTextArea::HandleEvent(MSG *msg, BOOL synthetic)
// 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);
}
......
......@@ -57,17 +57,11 @@ public:
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 @@ public:
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;
......
......@@ -66,6 +66,8 @@ AwtTextComponent::AwtTextComponent() {
m_lLastPos = -1;
m_isLFonly = FALSE;
m_EOLchecked = FALSE;
m_hEditCtrl = NULL;
m_bIgnoreEnChange = FALSE;
// javaEventsMask = 0; // accessibility support
}
......@@ -213,6 +215,16 @@ done:
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 @@ MsgRouting
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 @@ AwtTextComponent::HandleEvent(MSG *msg, BOOL synthetic)
{
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 @@ void AwtTextComponent::SetBackgroundColor(COLORREF c) {
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 @@ AwtTextComponent::OleCallback::GetContextMenu(WORD seltype,
}
/*
* 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
......
......@@ -47,6 +47,8 @@ public:
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 @@ public:
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 @@ public:
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 @@ private:
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
//
......
......@@ -249,13 +249,7 @@ AwtTextField::HandleEvent(MSG *msg, BOOL synthetic)
}
}
/*
* 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);
......
#!/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
/*
* 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);
}
}
}
/*
* 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;
}
}
......@@ -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;
......
......@@ -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 @@ public class IPv4Formats {
{"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 }
};
......
/*
* 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();
}
}
}
/*
* 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();
}
}
/*
* 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);
}
}
/*
* 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();
}
}
}
}
#! /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."
<?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>
/*
* 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);
}
}
}
}
}
}
}
}
/*
* 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");
}
}
}
......@@ -2502,7 +2502,7 @@ CalendarData/lt_LT/minimalDaysInFirstWeek=4
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/1=MMMM d, yyyy
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 @@ TimeZoneNames/de/WET/4=WESZ
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 @@ FormatData/es_DO/DatePatterns/3=dd/MM/yy
# 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=
......@@ -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
*
*/
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册