() {
+ public Void run() {
+ javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);
+ return null;
+ }
+ }, stack, srcAcc);
+ }
+ }
+
+ private static AccessControlContext getAccessControlContextFrom(Object src) {
+ return src instanceof Component ?
+ ((Component)src).getAccessControlContext() :
+ src instanceof MenuComponent ?
+ ((MenuComponent)src).getAccessControlContext() :
+ src instanceof TrayIcon ?
+ ((TrayIcon)src).getAccessControlContext() :
+ null;
+ }
+
+ /**
+ * Called from dispatchEvent() under a correct AccessControlContext
+ */
+ private void dispatchEventImpl(final AWTEvent event, final Object src) {
event.isPosted = true;
- Object src = event.getSource();
if (event instanceof ActiveEvent) {
// This could become the sole method of dispatching in time.
setCurrentEventAndMostRecentTimeImpl(event);
-
((ActiveEvent)event).dispatch();
} else if (src instanceof Component) {
((Component)src).dispatchEvent(event);
diff --git a/jdk/src/share/classes/java/awt/LinearGradientPaint.java b/jdk/src/share/classes/java/awt/LinearGradientPaint.java
index 8d5d727540b..7a60c7d4b6c 100644
--- a/jdk/src/share/classes/java/awt/LinearGradientPaint.java
+++ b/jdk/src/share/classes/java/awt/LinearGradientPaint.java
@@ -57,8 +57,14 @@ import java.beans.ConstructorProperties;
*
*
*
- * The user may also select what action the {@code LinearGradientPaint}
- * should take when filling color outside the start and end points.
+ * The user may also select what action the {@code LinearGradientPaint} object
+ * takes when it is filling the space outside the start and end points by
+ * setting {@code CycleMethod} to either {@code REFLECTION} or {@code REPEAT}.
+ * The distances between any two colors in any of the reflected or repeated
+ * copies of the gradient are the same as the distance between those same two
+ * colors between the start and end points.
+ * Note that some minor variations in distances may occur due to sampling at
+ * the granularity of a pixel.
* If no cycle method is specified, {@code NO_CYCLE} will be chosen by
* default, which means the endpoint colors will be used to fill the
* remaining area.
diff --git a/jdk/src/share/classes/java/awt/MenuComponent.java b/jdk/src/share/classes/java/awt/MenuComponent.java
index 19d57394a23..d1a5a2577b4 100644
--- a/jdk/src/share/classes/java/awt/MenuComponent.java
+++ b/jdk/src/share/classes/java/awt/MenuComponent.java
@@ -33,6 +33,9 @@ import sun.awt.SunToolkit;
import sun.awt.AWTAccessor;
import javax.accessibility.*;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+
/**
* The abstract class MenuComponent is the superclass
* of all menu-related components. In this respect, the class
@@ -99,6 +102,23 @@ public abstract class MenuComponent implements java.io.Serializable {
*/
boolean newEventsOnly = false;
+ /*
+ * The menu's AccessControlContext.
+ */
+ private transient volatile AccessControlContext acc =
+ AccessController.getContext();
+
+ /*
+ * Returns the acc this menu component was constructed with.
+ */
+ final AccessControlContext getAccessControlContext() {
+ if (acc == null) {
+ throw new SecurityException(
+ "MenuComponent is missing AccessControlContext");
+ }
+ return acc;
+ }
+
/*
* Internal constants for serialization.
*/
@@ -402,6 +422,9 @@ public abstract class MenuComponent implements java.io.Serializable {
throws ClassNotFoundException, IOException, HeadlessException
{
GraphicsEnvironment.checkHeadless();
+
+ acc = AccessController.getContext();
+
s.defaultReadObject();
appContext = AppContext.getAppContext();
diff --git a/jdk/src/share/classes/java/awt/MultipleGradientPaint.java b/jdk/src/share/classes/java/awt/MultipleGradientPaint.java
index 598f68f6f03..0dfaf5071ae 100644
--- a/jdk/src/share/classes/java/awt/MultipleGradientPaint.java
+++ b/jdk/src/share/classes/java/awt/MultipleGradientPaint.java
@@ -286,6 +286,10 @@ public abstract class MultipleGradientPaint implements Paint {
/**
* Returns a copy of the transform applied to the gradient.
*
+ *
+ * Note that if no transform is applied to the gradient
+ * when it is created, the identity transform is used.
+ *
* @return a copy of the transform applied to the gradient
*/
public final AffineTransform getTransform() {
@@ -293,10 +297,12 @@ public abstract class MultipleGradientPaint implements Paint {
}
/**
- * Returns the transparency mode for this Paint object.
+ * Returns the transparency mode for this {@code Paint} object.
*
- * @return an integer value representing the transparency mode for
- * this Paint object
+ * @return {@code OPAQUE} if all colors used by this
+ * {@code Paint} object are opaque,
+ * {@code TRANSLUCENT} if at least one of the
+ * colors used by this {@code Paint} object is not opaque.
* @see java.awt.Transparency
*/
public final int getTransparency() {
diff --git a/jdk/src/share/classes/java/awt/RadialGradientPaint.java b/jdk/src/share/classes/java/awt/RadialGradientPaint.java
index d87a3253d46..ee99c32d9de 100644
--- a/jdk/src/share/classes/java/awt/RadialGradientPaint.java
+++ b/jdk/src/share/classes/java/awt/RadialGradientPaint.java
@@ -71,8 +71,24 @@ import java.beans.ConstructorProperties;
*
*
*
- * The user may also select what action the {@code RadialGradientPaint}
- * should take when filling color outside the bounds of the circle's radius.
+ * The user may also select what action the {@code RadialGradientPaint} object
+ * takes when it is filling the space outside the circle's radius by
+ * setting {@code CycleMethod} to either {@code REFLECTION} or {@code REPEAT}.
+ * The gradient color proportions are equal for any particular line drawn
+ * from the focus point. The following figure shows that the distance AB
+ * is equal to the distance BC, and the distance AD is equal to the distance DE.
+ *
+ *
+ *
+ * If the gradient and graphics rendering transforms are uniformly scaled and
+ * the user sets the focus so that it coincides with the center of the circle,
+ * the gradient color proportions are equal for any line drawn from the center.
+ * The following figure shows the distances AB, BC, AD, and DE. They are all equal.
+ *
+ *
+ *
+ * Note that some minor variations in distances may occur due to sampling at
+ * the granularity of a pixel.
* If no cycle method is specified, {@code NO_CYCLE} will be chosen by
* default, which means the the last keyframe color will be used to fill the
* remaining area.
@@ -604,7 +620,7 @@ public final class RadialGradientPaint extends MultipleGradientPaint {
}
/**
- * Returns a copy of the end point of the gradient axis.
+ * Returns a copy of the focus point of the radial gradient.
*
* @return a {@code Point2D} object that is a copy of the focus point
*/
diff --git a/jdk/src/share/classes/java/awt/TrayIcon.java b/jdk/src/share/classes/java/awt/TrayIcon.java
index 35a98706e7f..13185bf92fd 100644
--- a/jdk/src/share/classes/java/awt/TrayIcon.java
+++ b/jdk/src/share/classes/java/awt/TrayIcon.java
@@ -40,6 +40,8 @@ import sun.awt.AppContext;
import sun.awt.SunToolkit;
import sun.awt.HeadlessToolkit;
import java.util.EventObject;
+import java.security.AccessControlContext;
+import java.security.AccessController;
/**
* A TrayIcon object represents a tray icon that can be
@@ -90,6 +92,7 @@ import java.util.EventObject;
* @author Anton Tarasov
*/
public class TrayIcon {
+
private Image image;
private String tooltip;
private PopupMenu popup;
@@ -103,6 +106,24 @@ public class TrayIcon {
transient MouseMotionListener mouseMotionListener;
transient ActionListener actionListener;
+ /*
+ * The tray icon's AccessControlContext.
+ *
+ * Unlike the acc in Component, this field is made final
+ * because TrayIcon is not serializable.
+ */
+ private final AccessControlContext acc = AccessController.getContext();
+
+ /*
+ * Returns the acc this tray icon was constructed with.
+ */
+ final AccessControlContext getAccessControlContext() {
+ if (acc == null) {
+ throw new SecurityException("TrayIcon is missing AccessControlContext");
+ }
+ return acc;
+ }
+
static {
Toolkit.loadLibraries();
if (!GraphicsEnvironment.isHeadless()) {
diff --git a/jdk/src/share/classes/java/awt/doc-files/RadialGradientPaint-3.png b/jdk/src/share/classes/java/awt/doc-files/RadialGradientPaint-3.png
new file mode 100644
index 00000000000..46484fdb766
Binary files /dev/null and b/jdk/src/share/classes/java/awt/doc-files/RadialGradientPaint-3.png differ
diff --git a/jdk/src/share/classes/java/awt/doc-files/RadialGradientPaint-4.png b/jdk/src/share/classes/java/awt/doc-files/RadialGradientPaint-4.png
new file mode 100644
index 00000000000..6ab38c833ce
Binary files /dev/null and b/jdk/src/share/classes/java/awt/doc-files/RadialGradientPaint-4.png differ
diff --git a/jdk/src/share/classes/java/awt/image/PackedColorModel.java b/jdk/src/share/classes/java/awt/image/PackedColorModel.java
index 532f8d2678b..b2ab7ad9c91 100644
--- a/jdk/src/share/classes/java/awt/image/PackedColorModel.java
+++ b/jdk/src/share/classes/java/awt/image/PackedColorModel.java
@@ -343,8 +343,13 @@ public abstract class PackedColorModel extends ColorModel {
if (bitMasks.length != maskArray.length) {
return false;
}
+
+ /* compare 'effective' masks only, i.e. only part of the mask
+ * which fits the capacity of the transfer type.
+ */
+ int maxMask = (int)((1L << DataBuffer.getDataTypeSize(transferType)) - 1);
for (int i=0; i < bitMasks.length; i++) {
- if (bitMasks[i] != maskArray[i]) {
+ if ((maxMask & bitMasks[i]) != (maxMask & maskArray[i])) {
return false;
}
}
diff --git a/jdk/src/share/classes/java/beans/DefaultPersistenceDelegate.java b/jdk/src/share/classes/java/beans/DefaultPersistenceDelegate.java
index d5c24edcb64..64570928afb 100644
--- a/jdk/src/share/classes/java/beans/DefaultPersistenceDelegate.java
+++ b/jdk/src/share/classes/java/beans/DefaultPersistenceDelegate.java
@@ -35,7 +35,7 @@ import sun.reflect.misc.*;
* is the delegate used by default for classes about
* which no information is available. The DefaultPersistenceDelegate
* provides, version resilient, public API-based persistence for
- * classes that follow the JavaBeans conventions without any class specific
+ * classes that follow the JavaBeans™ conventions without any class specific
* configuration.
*
* The key assumptions are that the class has a nullary constructor
diff --git a/jdk/src/share/classes/java/beans/DesignMode.java b/jdk/src/share/classes/java/beans/DesignMode.java
index 3080706c5a0..af86266dc3f 100644
--- a/jdk/src/share/classes/java/beans/DesignMode.java
+++ b/jdk/src/share/classes/java/beans/DesignMode.java
@@ -31,7 +31,7 @@ package java.beans;
* of java.beans.beancontext.BeanContext, in order to propagate to its nested hierarchy
* of java.beans.beancontext.BeanContextChild instances, the current "designTime" property.
*
- * The JavaBeans specification defines the notion of design time as is a
+ * The JavaBeans™ specification defines the notion of design time as is a
* mode in which JavaBeans instances should function during their composition
* and customization in a interactive design, composition or construction tool,
* as opposed to runtime when the JavaBean is part of an applet, application,
diff --git a/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java b/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java
index a255ccabd8b..7ec03d8fb75 100644
--- a/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java
+++ b/jdk/src/share/classes/java/beans/IndexedPropertyChangeEvent.java
@@ -26,7 +26,7 @@ package java.beans;
/**
* An "IndexedPropertyChange" event gets delivered whenever a component that
- * conforms to the JavaBeans specification (a "bean") changes a bound
+ * conforms to the JavaBeans™ specification (a "bean") changes a bound
* indexed property. This class is an extension of PropertyChangeEvent
* but contains the index of the property that has changed.
*
diff --git a/jdk/src/share/classes/java/beans/Introspector.java b/jdk/src/share/classes/java/beans/Introspector.java
index 9046da81719..5892df6cb29 100644
--- a/jdk/src/share/classes/java/beans/Introspector.java
+++ b/jdk/src/share/classes/java/beans/Introspector.java
@@ -87,7 +87,7 @@ import sun.reflect.misc.ReflectUtil;
*
* For more information about introspection and design patterns, please
* consult the
- * JavaBeans specification .
+ * JavaBeans™ specification .
*/
public class Introspector {
@@ -1245,7 +1245,7 @@ public class Introspector {
try {
type = ClassFinder.findClass(name, type.getClassLoader());
// Each customizer should inherit java.awt.Component and implement java.beans.Customizer
- // according to the section 9.3 of JavaBeans specification
+ // according to the section 9.3 of JavaBeans™ specification
if (Component.class.isAssignableFrom(type) && Customizer.class.isAssignableFrom(type)) {
return type;
}
diff --git a/jdk/src/share/classes/java/beans/VetoableChangeSupport.java b/jdk/src/share/classes/java/beans/VetoableChangeSupport.java
index a8573da5fc9..d26f58a219d 100644
--- a/jdk/src/share/classes/java/beans/VetoableChangeSupport.java
+++ b/jdk/src/share/classes/java/beans/VetoableChangeSupport.java
@@ -474,7 +474,7 @@ public class VetoableChangeSupport implements Serializable {
/**
* @serialField children Hashtable
* @serialField source Object
- * @serialField propertyChangeSupportSerializedDataVersion int
+ * @serialField vetoableChangeSupportSerializedDataVersion int
*/
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("children", Hashtable.class),
diff --git a/jdk/src/share/classes/java/beans/package.html b/jdk/src/share/classes/java/beans/package.html
index 576e1f763dc..b1f0a8cf336 100644
--- a/jdk/src/share/classes/java/beans/package.html
+++ b/jdk/src/share/classes/java/beans/package.html
@@ -29,7 +29,7 @@
Contains classes related to developing
beans -- components
-based on the JavaBeansTM architecture.
+based on the JavaBeans™ architecture.
A few of the
classes are used by beans while they run in an application.
For example, the event classes are
diff --git a/jdk/src/share/classes/java/dyn/Linkage.java b/jdk/src/share/classes/java/dyn/Linkage.java
deleted file mode 100644
index 4ddda0a1990..00000000000
--- a/jdk/src/share/classes/java/dyn/Linkage.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2008, 2010, 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 java.dyn;
-
-import java.dyn.MethodHandles.Lookup;
-import java.util.WeakHashMap;
-import sun.dyn.Access;
-import sun.dyn.MethodHandleImpl;
-import sun.dyn.util.VerifyAccess;
-import sun.reflect.Reflection;
-import static sun.dyn.MemberName.newIllegalArgumentException;
-
-/**
- * CLASS WILL BE REMOVED FOR PFD:
- * Static routines for controlling invokedynamic behavior.
- * Replaced by non-static APIs.
- * @author John Rose, JSR 292 EG
- * @deprecated This class will be removed in the Public Final Draft.
- */
-public class Linkage {
- private static final Access IMPL_TOKEN = Access.getToken();
-
- private Linkage() {} // do not instantiate
-
- /**
- * METHOD WILL BE REMOVED FOR PFD:
- * Register a bootstrap method to use when linking dynamic call sites within
- * a given caller class.
- * @deprecated Use @{@link BootstrapMethod} annotations instead.
- */
- public static
- void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
- Class callc = Reflection.getCallerClass(2);
- if (callc != null && !VerifyAccess.isSamePackage(callerClass, callc))
- throw new IllegalArgumentException("cannot set bootstrap method on "+callerClass);
- MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
- }
-
- /**
- * METHOD WILL BE REMOVED FOR PFD:
- * Simplified version of {@code registerBootstrapMethod} for self-registration,
- * to be called from a static initializer.
- * @deprecated Use @{@link BootstrapMethod} annotations instead.
- */
- public static
- void registerBootstrapMethod(Class> runtime, String name) {
- Class callerClass = Reflection.getCallerClass(2);
- registerBootstrapMethodLookup(callerClass, runtime, name);
- }
-
- /**
- * METHOD WILL BE REMOVED FOR PFD:
- * Simplified version of {@code registerBootstrapMethod} for self-registration,
- * @deprecated Use @{@link BootstrapMethod} annotations instead.
- */
- public static
- void registerBootstrapMethod(String name) {
- Class callerClass = Reflection.getCallerClass(2);
- registerBootstrapMethodLookup(callerClass, callerClass, name);
- }
-
- private static
- void registerBootstrapMethodLookup(Class> callerClass, Class> runtime, String name) {
- Lookup lookup = new Lookup(IMPL_TOKEN, callerClass);
- MethodHandle bootstrapMethod;
- try {
- bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
- } catch (ReflectiveOperationException ex) {
- throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
- }
- MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
- }
-
- private static final MethodType BOOTSTRAP_METHOD_TYPE
- = MethodType.methodType(CallSite.class,
- Class.class, String.class, MethodType.class);
-
- /**
- * METHOD WILL BE REMOVED FOR PFD:
- * Invalidate all invokedynamic call sites everywhere.
- * @deprecated Use {@linkplain MutableCallSite#setTarget call site target setting},
- * {@link MutableCallSite#syncAll call site update pushing},
- * and {@link SwitchPoint#guardWithTest target switching} instead.
- */
- public static
- Object invalidateAll() {
- throw new UnsupportedOperationException();
- }
-
- /**
- * METHOD WILL BE REMOVED FOR PFD:
- * Invalidate all {@code invokedynamic} call sites in the bytecodes
- * of any methods of the given class.
- * @deprecated Use {@linkplain MutableCallSite#setTarget call site target setting},
- * {@link MutableCallSite#syncAll call site update pushing},
- * and {@link SwitchPoint#guardWithTest target switching} instead.
- */
- public static
- Object invalidateCallerClass(Class> callerClass) {
- throw new UnsupportedOperationException();
- }
-}
diff --git a/jdk/src/share/classes/java/lang/AutoCloseable.java b/jdk/src/share/classes/java/lang/AutoCloseable.java
index f18de8cd5fb..54ecda38fed 100644
--- a/jdk/src/share/classes/java/lang/AutoCloseable.java
+++ b/jdk/src/share/classes/java/lang/AutoCloseable.java
@@ -34,12 +34,27 @@ package java.lang;
public interface AutoCloseable {
/**
* Closes this resource, relinquishing any underlying resources.
- * This method is invoked automatically by the {@code
- * try}-with-resources statement.
+ * This method is invoked automatically on objects managed by the
+ * {@code try}-with-resources statement.
*
- *
Classes implementing this method are strongly encouraged to
- * be declared to throw more specific exceptions (or no exception
- * at all, if the close cannot fail).
+ *
While this interface method is declared to throw {@code
+ * Exception}, implementers are strongly encouraged to
+ * declare concrete implementations of the {@code close} method to
+ * throw more specific exceptions, or to throw no exception at all
+ * if the close operation cannot fail.
+ *
+ *
Implementers of this interface are also strongly advised
+ * to not have the {@code close} method throw {@link
+ * InterruptedException}.
+ *
+ * This exception interacts with a thread's interrupted status,
+ * and runtime misbehavior is likely to occur if an {@code
+ * InterruptedException} is {@linkplain Throwable#addSuppressed
+ * suppressed}.
+ *
+ * More generally, if it would cause problems for an
+ * exception to be suppressed, the {@code AutoCloseable.close}
+ * method should not throw it.
*
*
Note that unlike the {@link java.io.Closeable#close close}
* method of {@link java.io.Closeable}, this {@code close} method
@@ -48,9 +63,8 @@ public interface AutoCloseable {
* visible side effect, unlike {@code Closeable.close} which is
* required to have no effect if called more than once.
*
- * However, while not required to be idempotent, implementers of
- * this interface are strongly encouraged to make their {@code
- * close} methods idempotent.
+ * However, implementers of this interface are strongly encouraged
+ * to make their {@code close} methods idempotent.
*
* @throws Exception if this resource cannot be closed
*/
diff --git a/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java b/jdk/src/share/classes/java/lang/BootstrapMethodError.java
similarity index 66%
rename from jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
rename to jdk/src/share/classes/java/lang/BootstrapMethodError.java
index 76e795e2f0e..0fee75ad33d 100644
--- a/jdk/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
+++ b/jdk/src/share/classes/java/lang/BootstrapMethodError.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,58 +23,56 @@
* questions.
*/
-package java.dyn;
+package java.lang;
/**
* Thrown to indicate that an {@code invokedynamic} instruction has
- * failed to find its
- * {@linkplain BootstrapMethod bootstrap method},
- * or the bootstrap method has
- * failed to provide a
- * {@linkplain CallSite call site} with a {@linkplain CallSite#getTarget target}
- * of the correct {@linkplain MethodHandle#type method type}.
+ * failed to find its bootstrap method,
+ * or the bootstrap method has failed to provide a
+ * {@linkplain java.lang.invoke.CallSite call site} with a {@linkplain java.lang.invoke.CallSite#getTarget target}
+ * of the correct {@linkplain java.lang.invoke.MethodHandle#type method type}.
*
* @author John Rose, JSR 292 EG
* @since 1.7
*/
-public class InvokeDynamicBootstrapError extends LinkageError {
+public class BootstrapMethodError extends LinkageError {
private static final long serialVersionUID = 292L;
/**
- * Constructs an {@code InvokeDynamicBootstrapError} with no detail message.
+ * Constructs an {@code BootstrapMethodError} with no detail message.
*/
- public InvokeDynamicBootstrapError() {
+ public BootstrapMethodError() {
super();
}
/**
- * Constructs an {@code InvokeDynamicBootstrapError} with the specified
+ * Constructs an {@code BootstrapMethodError} with the specified
* detail message.
*
* @param s the detail message.
*/
- public InvokeDynamicBootstrapError(String s) {
+ public BootstrapMethodError(String s) {
super(s);
}
/**
- * Constructs a {@code InvokeDynamicBootstrapError} with the specified
+ * Constructs a {@code BootstrapMethodError} with the specified
* detail message and cause.
*
* @param s the detail message.
* @param cause the cause, may be {@code null}.
*/
- public InvokeDynamicBootstrapError(String s, Throwable cause) {
+ public BootstrapMethodError(String s, Throwable cause) {
super(s, cause);
}
/**
- * Constructs a {@code InvokeDynamicBootstrapError} with the specified
+ * Constructs a {@code BootstrapMethodError} with the specified
* cause.
*
* @param cause the cause, may be {@code null}.
*/
- public InvokeDynamicBootstrapError(Throwable cause) {
+ public BootstrapMethodError(Throwable cause) {
// cf. Throwable(Throwable cause) constructor.
super(cause == null ? null : cause.toString());
initCause(cause);
diff --git a/jdk/src/share/classes/java/lang/ClassLoader.java b/jdk/src/share/classes/java/lang/ClassLoader.java
index 37d7a30b583..2c0c7908566 100644
--- a/jdk/src/share/classes/java/lang/ClassLoader.java
+++ b/jdk/src/share/classes/java/lang/ClassLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2011, 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
@@ -1626,20 +1626,28 @@ public abstract class ClassLoader {
* @since 1.2
*/
protected Package getPackage(String name) {
+ Package pkg;
synchronized (packages) {
- Package pkg = packages.get(name);
- if (pkg == null) {
- if (parent != null) {
- pkg = parent.getPackage(name);
- } else {
- pkg = Package.getSystemPackage(name);
- }
- if (pkg != null) {
- packages.put(name, pkg);
+ pkg = packages.get(name);
+ }
+ if (pkg == null) {
+ if (parent != null) {
+ pkg = parent.getPackage(name);
+ } else {
+ pkg = Package.getSystemPackage(name);
+ }
+ if (pkg != null) {
+ synchronized (packages) {
+ Package pkg2 = packages.get(name);
+ if (pkg2 == null) {
+ packages.put(name, pkg);
+ } else {
+ pkg = pkg2;
+ }
}
}
- return pkg;
}
+ return pkg;
}
/**
diff --git a/jdk/src/share/classes/java/dyn/ClassValue.java b/jdk/src/share/classes/java/lang/ClassValue.java
similarity index 94%
rename from jdk/src/share/classes/java/dyn/ClassValue.java
rename to jdk/src/share/classes/java/lang/ClassValue.java
index 597dd951eb6..92c49a92ef2 100644
--- a/jdk/src/share/classes/java/dyn/ClassValue.java
+++ b/jdk/src/share/classes/java/lang/ClassValue.java
@@ -23,12 +23,10 @@
* questions.
*/
-package java.dyn;
+package java.lang;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.lang.reflect.UndeclaredThrowableException;
/**
* Lazily associate a computed value with (potentially) every type.
@@ -37,10 +35,11 @@ import java.lang.reflect.UndeclaredThrowableException;
* it can use a {@code ClassValue} to cache information needed to
* perform the message send quickly, for each class encountered.
* @author John Rose, JSR 292 EG
+ * @since 1.7
*/
public abstract class ClassValue {
/**
- * Compute the given class's derived value for this {@code ClassValue}.
+ * Computes the given class's derived value for this {@code ClassValue}.
*
* This method will be invoked within the first thread that accesses
* the value with the {@link #get get} method.
@@ -159,13 +158,7 @@ public abstract class ClassValue {
}
/// Implementation...
-
- // The hash code for this type is based on the identity of the object,
- // and is well-dispersed for power-of-two tables.
- /** @deprecated This override, which is implementation-specific, will be removed for PFD. */
- public final int hashCode() { return hashCode; }
- private final int hashCode = HASH_CODES.getAndAdd(0x61c88647);
- private static final AtomicInteger HASH_CODES = new AtomicInteger();
+ // FIXME: Use a data structure here similar that of ThreadLocal (7030453).
private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
diff --git a/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java b/jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java
similarity index 89%
rename from jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java
rename to jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java
index 676907c9185..a47b38f8bb3 100644
--- a/jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java
+++ b/jdk/src/share/classes/java/lang/invoke/AdapterMethodHandle.java
@@ -23,20 +23,19 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import sun.dyn.util.VerifyType;
-import sun.dyn.util.Wrapper;
-import java.dyn.*;
+import sun.invoke.util.VerifyType;
+import sun.invoke.util.Wrapper;
import java.util.Arrays;
-import static sun.dyn.MethodHandleNatives.Constants.*;
-import static sun.dyn.MemberName.newIllegalArgumentException;
+import static java.lang.invoke.MethodHandleNatives.Constants.*;
+import static java.lang.invoke.MethodHandleStatics.*;
/**
* This method handle performs simple conversion or checking of a single argument.
* @author jrose
*/
-public class AdapterMethodHandle extends BoundMethodHandle {
+class AdapterMethodHandle extends BoundMethodHandle {
//MethodHandle vmtarget; // next AMH or BMH in chain or final DMH
//Object argument; // parameter to the conversion if needed
@@ -48,25 +47,21 @@ public class AdapterMethodHandle extends BoundMethodHandle {
long conv, Object convArg) {
super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv)));
this.conversion = convCode(conv);
- if (MethodHandleNatives.JVM_SUPPORT) {
- // JVM might update VM-specific bits of conversion (ignore)
- MethodHandleNatives.init(this, target, convArgPos(conv));
- }
+ // JVM might update VM-specific bits of conversion (ignore)
+ MethodHandleNatives.init(this, target, convArgPos(conv));
}
private AdapterMethodHandle(MethodHandle target, MethodType newType,
long conv) {
this(target, newType, conv, null);
}
- private static final Access IMPL_TOKEN = Access.getToken();
-
// TO DO: When adapting another MH with a null conversion, clone
// the target and change its type, instead of adding another layer.
/** Can a JVM-level adapter directly implement the proposed
* argument conversions, as if by MethodHandles.convertArguments?
*/
- public static boolean canPairwiseConvert(MethodType newType, MethodType oldType) {
+ static boolean canPairwiseConvert(MethodType newType, MethodType oldType) {
// same number of args, of course
int len = newType.parameterCount();
if (len != oldType.parameterCount())
@@ -92,7 +87,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Can a JVM-level adapter directly implement the proposed
* argument conversion, as if by MethodHandles.convertArguments?
*/
- public static boolean canConvertArgument(Class> src, Class> dst) {
+ static boolean canConvertArgument(Class> src, Class> dst) {
// ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
// so we don't need to repeat so much decision making.
if (VerifyType.isNullConversion(src, dst)) {
@@ -118,16 +113,13 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* the JVM supports ricochet adapters).
* The argument conversions allowed are casting, unboxing,
* integral widening or narrowing, and floating point widening or narrowing.
- * @param token access check
* @param newType required call type
* @param target original method handle
* @return an adapter to the original handle with the desired new type,
* or the original target if the types are already identical
* or null if the adaptation cannot be made
*/
- public static MethodHandle makePairwiseConvert(Access token,
- MethodType newType, MethodHandle target) {
- Access.check(token);
+ static MethodHandle makePairwiseConvert(MethodType newType, MethodHandle target) {
MethodType oldType = target.type();
if (newType == oldType) return target;
@@ -170,9 +162,9 @@ public class AdapterMethodHandle extends BoundMethodHandle {
// It parallels canConvertArgument() above.
if (src.isPrimitive()) {
if (dst.isPrimitive()) {
- adapter = makePrimCast(token, midType, adapter, i, dst);
+ adapter = makePrimCast(midType, adapter, i, dst);
} else {
- adapter = makeBoxArgument(token, midType, adapter, i, dst);
+ adapter = makeBoxArgument(midType, adapter, i, dst);
}
} else {
if (dst.isPrimitive()) {
@@ -182,13 +174,13 @@ public class AdapterMethodHandle extends BoundMethodHandle {
// conversions supported by reflect.Method.invoke.
// Those conversions require a big nest of if/then/else logic,
// which we prefer to make a user responsibility.
- adapter = makeUnboxArgument(token, midType, adapter, i, dst);
+ adapter = makeUnboxArgument(midType, adapter, i, dst);
} else {
// Simple reference conversion.
// Note: Do not check for a class hierarchy relation
// between src and dst. In all cases a 'null' argument
// will pass the cast conversion.
- adapter = makeCheckCast(token, midType, adapter, i, dst);
+ adapter = makeCheckCast(midType, adapter, i, dst);
}
}
assert(adapter != null);
@@ -196,7 +188,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
if (adapter.type() != newType) {
// Only trivial conversions remain.
- adapter = makeRetypeOnly(IMPL_TOKEN, newType, adapter);
+ adapter = makeRetypeOnly(newType, adapter);
assert(adapter != null);
// Actually, that's because there were no non-trivial ones:
assert(lastConv == -1);
@@ -208,7 +200,6 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/**
* Create a JVM-level adapter method handle to permute the arguments
* of the given method.
- * @param token access check
* @param newType required call type
* @param target original method handle
* @param argumentMap for each target argument, position of its source in newType
@@ -218,8 +209,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* @throws IllegalArgumentException if the adaptation cannot be made
* directly by a JVM-level adapter, without help from Java code
*/
- public static MethodHandle makePermutation(Access token,
- MethodType newType, MethodHandle target,
+ static MethodHandle makePermutation(MethodType newType, MethodHandle target,
int[] argumentMap) {
MethodType oldType = target.type();
boolean nullPermutation = true;
@@ -234,7 +224,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
if (argumentMap.length != oldType.parameterCount())
throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap));
if (nullPermutation) {
- MethodHandle res = makePairwiseConvert(token, newType, target);
+ MethodHandle res = makePairwiseConvert(newType, target);
// well, that was easy
if (res == null)
throw newIllegalArgumentException("cannot convert pairwise: "+newType);
@@ -435,7 +425,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
/** Can a retyping adapter (alone) validly convert the target to newType? */
- public static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
+ static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
return canRetype(newType, targetType, false);
}
/** Can a retyping adapter (alone) convert the target to newType?
@@ -444,7 +434,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* reference conversions on return. This last feature requires that the
* caller be trusted, and perform explicit cast conversions on return values.
*/
- public static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
+ static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
return canRetype(newType, targetType, true);
}
static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) {
@@ -459,17 +449,13 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* Allows unchecked argument conversions pairwise, if they are safe.
* Returns null if not possible.
*/
- public static MethodHandle makeRetypeOnly(Access token,
- MethodType newType, MethodHandle target) {
- return makeRetype(token, newType, target, false);
+ static MethodHandle makeRetypeOnly(MethodType newType, MethodHandle target) {
+ return makeRetype(newType, target, false);
}
- public static MethodHandle makeRetypeRaw(Access token,
- MethodType newType, MethodHandle target) {
- return makeRetype(token, newType, target, true);
+ static MethodHandle makeRetypeRaw(MethodType newType, MethodHandle target) {
+ return makeRetype(newType, target, true);
}
- static MethodHandle makeRetype(Access token,
- MethodType newType, MethodHandle target, boolean raw) {
- Access.check(token);
+ static MethodHandle makeRetype(MethodType newType, MethodHandle target, boolean raw) {
MethodType oldType = target.type();
if (oldType == newType) return target;
if (!canRetype(newType, oldType, raw))
@@ -478,9 +464,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
}
- static MethodHandle makeVarargsCollector(Access token,
- MethodHandle target, Class> arrayType) {
- Access.check(token);
+ static MethodHandle makeVarargsCollector(MethodHandle target, Class> arrayType) {
return new AsVarargsCollector(target, arrayType);
}
@@ -526,6 +510,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return collector.asType(newType);
}
+ @Override
public MethodHandle asVarargsCollector(Class> arrayType) {
MethodType type = this.type();
if (type.parameterType(type.parameterCount()-1) == arrayType)
@@ -537,7 +522,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Can a checkcast adapter validly convert the target to newType?
* The JVM supports all kind of reference casts, even silly ones.
*/
- public static boolean canCheckCast(MethodType newType, MethodType targetType,
+ static boolean canCheckCast(MethodType newType, MethodType targetType,
int arg, Class> castType) {
if (!convOpSupported(OP_CHECK_CAST)) return false;
Class> src = newType.parameterType(arg);
@@ -549,7 +534,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return (diff == arg+1); // arg is sole non-trivial diff
}
/** Can an primitive conversion adapter validly convert src to dst? */
- public static boolean canCheckCast(Class> src, Class> dst) {
+ static boolean canCheckCast(Class> src, Class> dst) {
return (!src.isPrimitive() && !dst.isPrimitive());
}
@@ -558,10 +543,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* with a null conversion to the corresponding target parameter.
* Return null if this cannot be done.
*/
- public static MethodHandle makeCheckCast(Access token,
- MethodType newType, MethodHandle target,
+ static MethodHandle makeCheckCast(MethodType newType, MethodHandle target,
int arg, Class> castType) {
- Access.check(token);
if (!canCheckCast(newType, target.type(), arg, castType))
return null;
long conv = makeConv(OP_CHECK_CAST, arg, T_OBJECT, T_OBJECT);
@@ -572,7 +555,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* The JVM currently supports all conversions except those between
* floating and integral types.
*/
- public static boolean canPrimCast(MethodType newType, MethodType targetType,
+ static boolean canPrimCast(MethodType newType, MethodType targetType,
int arg, Class> convType) {
if (!convOpSupported(OP_PRIM_TO_PRIM)) return false;
Class> src = newType.parameterType(arg);
@@ -584,7 +567,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return (diff == arg+1); // arg is sole non-trivial diff
}
/** Can an primitive conversion adapter validly convert src to dst? */
- public static boolean canPrimCast(Class> src, Class> dst) {
+ static boolean canPrimCast(Class> src, Class> dst) {
if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) {
return false;
} else if (Wrapper.forPrimitiveType(dst).isFloating()) {
@@ -604,10 +587,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* with a null conversion to the corresponding target parameter.
* Return null if this cannot be done.
*/
- public static MethodHandle makePrimCast(Access token,
- MethodType newType, MethodHandle target,
+ static MethodHandle makePrimCast(MethodType newType, MethodHandle target,
int arg, Class> convType) {
- Access.check(token);
MethodType oldType = target.type();
if (!canPrimCast(newType, oldType, arg, convType))
return null;
@@ -620,7 +601,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* The JVM currently supports all kinds of casting and unboxing.
* The convType is the unboxed type; it can be either a primitive or wrapper.
*/
- public static boolean canUnboxArgument(MethodType newType, MethodType targetType,
+ static boolean canUnboxArgument(MethodType newType, MethodType targetType,
int arg, Class> convType) {
if (!convOpSupported(OP_REF_TO_PRIM)) return false;
Class> src = newType.parameterType(arg);
@@ -635,15 +616,14 @@ public class AdapterMethodHandle extends BoundMethodHandle {
return (diff == arg+1); // arg is sole non-trivial diff
}
/** Can an primitive unboxing adapter validly convert src to dst? */
- public static boolean canUnboxArgument(Class> src, Class> dst) {
+ static boolean canUnboxArgument(Class> src, Class> dst) {
return (!src.isPrimitive() && Wrapper.asPrimitiveType(dst).isPrimitive());
}
/** Factory method: Unbox the given argument.
* Return null if this cannot be done.
*/
- public static MethodHandle makeUnboxArgument(Access token,
- MethodType newType, MethodHandle target,
+ static MethodHandle makeUnboxArgument(MethodType newType, MethodHandle target,
int arg, Class> convType) {
MethodType oldType = target.type();
Class> src = newType.parameterType(arg);
@@ -659,11 +639,11 @@ public class AdapterMethodHandle extends BoundMethodHandle {
MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
if (castDone == newType)
return adapter;
- return makeCheckCast(token, newType, adapter, arg, boxType);
+ return makeCheckCast(newType, adapter, arg, boxType);
}
/** Can an primitive boxing adapter validly convert src to dst? */
- public static boolean canBoxArgument(Class> src, Class> dst) {
+ static boolean canBoxArgument(Class> src, Class> dst) {
if (!convOpSupported(OP_PRIM_TO_REF)) return false;
throw new UnsupportedOperationException("NYI");
}
@@ -671,15 +651,14 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Unbox the given argument.
* Return null if this cannot be done.
*/
- public static MethodHandle makeBoxArgument(Access token,
- MethodType newType, MethodHandle target,
+ static MethodHandle makeBoxArgument(MethodType newType, MethodHandle target,
int arg, Class> convType) {
// this is difficult to do in the JVM because it must GC
return null;
}
/** Can an adapter simply drop arguments to convert the target to newType? */
- public static boolean canDropArguments(MethodType newType, MethodType targetType,
+ static boolean canDropArguments(MethodType newType, MethodType targetType,
int dropArgPos, int dropArgCount) {
if (dropArgCount == 0)
return canRetypeOnly(newType, targetType);
@@ -706,12 +685,10 @@ public class AdapterMethodHandle extends BoundMethodHandle {
* Allow unchecked retyping of remaining arguments, pairwise.
* Return null if this is not possible.
*/
- public static MethodHandle makeDropArguments(Access token,
- MethodType newType, MethodHandle target,
+ static MethodHandle makeDropArguments(MethodType newType, MethodHandle target,
int dropArgPos, int dropArgCount) {
- Access.check(token);
if (dropArgCount == 0)
- return makeRetypeOnly(IMPL_TOKEN, newType, target);
+ return makeRetypeOnly(newType, target);
if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount))
return null;
// in arglist: [0: ...keep1 | dpos: drop... | dpos+dcount: keep2... ]
@@ -727,7 +704,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
/** Can an adapter duplicate an argument to convert the target to newType? */
- public static boolean canDupArguments(MethodType newType, MethodType targetType,
+ static boolean canDupArguments(MethodType newType, MethodType targetType,
int dupArgPos, int dupArgCount) {
if (!convOpSupported(OP_DUP_ARGS)) return false;
if (diffReturnTypes(newType, targetType, false) != 0)
@@ -749,10 +726,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Duplicate the selected argument.
* Return null if this is not possible.
*/
- public static MethodHandle makeDupArguments(Access token,
- MethodType newType, MethodHandle target,
+ static MethodHandle makeDupArguments(MethodType newType, MethodHandle target,
int dupArgPos, int dupArgCount) {
- Access.check(token);
if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount))
return null;
if (dupArgCount == 0)
@@ -769,7 +744,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
/** Can an adapter swap two arguments to convert the target to newType? */
- public static boolean canSwapArguments(MethodType newType, MethodType targetType,
+ static boolean canSwapArguments(MethodType newType, MethodType targetType,
int swapArg1, int swapArg2) {
if (!convOpSupported(OP_SWAP_ARGS)) return false;
if (diffReturnTypes(newType, targetType, false) != 0)
@@ -796,10 +771,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Swap the selected arguments.
* Return null if this is not possible.
*/
- public static MethodHandle makeSwapArguments(Access token,
- MethodType newType, MethodHandle target,
+ static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target,
int swapArg1, int swapArg2) {
- Access.check(token);
if (swapArg1 == swapArg2)
return target;
if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
@@ -829,7 +802,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
final static int MAX_ARG_ROTATION = 1;
/** Can an adapter rotate arguments to convert the target to newType? */
- public static boolean canRotateArguments(MethodType newType, MethodType targetType,
+ static boolean canRotateArguments(MethodType newType, MethodType targetType,
int firstArg, int argCount, int rotateBy) {
if (!convOpSupported(OP_ROT_ARGS)) return false;
if (argCount <= 2) return false; // must be a swap, not a rotate
@@ -861,10 +834,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Rotate the selected argument range.
* Return null if this is not possible.
*/
- public static MethodHandle makeRotateArguments(Access token,
- MethodType newType, MethodHandle target,
+ static MethodHandle makeRotateArguments(MethodType newType, MethodHandle target,
int firstArg, int argCount, int rotateBy) {
- Access.check(token);
rotateBy = positiveRotation(argCount, rotateBy);
if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy))
return null;
@@ -904,7 +875,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
}
/** Can an adapter spread an argument to convert the target to newType? */
- public static boolean canSpreadArguments(MethodType newType, MethodType targetType,
+ static boolean canSpreadArguments(MethodType newType, MethodType targetType,
Class> spreadArgType, int spreadArgPos, int spreadArgCount) {
if (!convOpSupported(OP_SPREAD_ARGS)) return false;
if (diffReturnTypes(newType, targetType, false) != 0)
@@ -937,10 +908,8 @@ public class AdapterMethodHandle extends BoundMethodHandle {
/** Factory method: Spread selected argument. */
- public static MethodHandle makeSpreadArguments(Access token,
- MethodType newType, MethodHandle target,
+ static MethodHandle makeSpreadArguments(MethodType newType, MethodHandle target,
Class> spreadArgType, int spreadArgPos, int spreadArgCount) {
- Access.check(token);
MethodType targetType = target.type();
if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
return null;
@@ -962,7 +931,7 @@ public class AdapterMethodHandle extends BoundMethodHandle {
@Override
public String toString() {
- return MethodHandleImpl.getNameString(IMPL_TOKEN, nonAdapter((MethodHandle)vmtarget), this);
+ return getNameString(nonAdapter((MethodHandle)vmtarget), this);
}
private static MethodHandle nonAdapter(MethodHandle mh) {
diff --git a/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java
similarity index 80%
rename from jdk/src/share/classes/sun/dyn/BoundMethodHandle.java
rename to jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java
index 0fab63f7c77..d0d78895e77 100644
--- a/jdk/src/share/classes/sun/dyn/BoundMethodHandle.java
+++ b/jdk/src/share/classes/java/lang/invoke/BoundMethodHandle.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,15 +23,11 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import sun.dyn.util.VerifyType;
-import sun.dyn.util.Wrapper;
-import java.dyn.*;
-import java.util.List;
-import sun.dyn.MethodHandleNatives.Constants;
-import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP;
-import static sun.dyn.MemberName.newIllegalArgumentException;
+import sun.invoke.util.VerifyType;
+import sun.invoke.util.Wrapper;
+import static java.lang.invoke.MethodHandleStatics.*;
/**
* The flavor of method handle which emulates an invoke instruction
@@ -39,37 +35,29 @@ import static sun.dyn.MemberName.newIllegalArgumentException;
* when the handle is created, not when it is invoked.
* @author jrose
*/
-public class BoundMethodHandle extends MethodHandle {
+class BoundMethodHandle extends MethodHandle {
//MethodHandle vmtarget; // next BMH or final DMH or methodOop
private final Object argument; // argument to insert
private final int vmargslot; // position at which it is inserted
- private static final Access IMPL_TOKEN = Access.getToken();
- private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
-
// Constructors in this class *must* be package scoped or private.
/** Bind a direct MH to its receiver (or first ref. argument).
* The JVM will pre-dispatch the MH if it is not already static.
*/
- BoundMethodHandle(DirectMethodHandle mh, Object argument) {
- super(Access.TOKEN, mh.type().dropParameterTypes(0, 1));
+ /*non-public*/ BoundMethodHandle(DirectMethodHandle mh, Object argument) {
+ super(mh.type().dropParameterTypes(0, 1));
// check the type now, once for all:
this.argument = checkReferenceArgument(argument, mh, 0);
this.vmargslot = this.type().parameterSlotCount();
- if (MethodHandleNatives.JVM_SUPPORT) {
- this.vmtarget = null; // maybe updated by JVM
- MethodHandleNatives.init(this, mh, 0);
- } else {
- this.vmtarget = mh;
- }
+ initTarget(mh, 0);
}
/** Insert an argument into an arbitrary method handle.
* If argnum is zero, inserts the first argument, etc.
* The argument type must be a reference.
*/
- BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
+ /*non-public*/ BoundMethodHandle(MethodHandle mh, Object argument, int argnum) {
this(mh.type().dropParameterTypes(argnum, argnum+1),
mh, argument, argnum);
}
@@ -77,8 +65,8 @@ public class BoundMethodHandle extends MethodHandle {
/** Insert an argument into an arbitrary method handle.
* If argnum is zero, inserts the first argument, etc.
*/
- BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) {
- super(Access.TOKEN, type);
+ /*non-public*/ BoundMethodHandle(MethodType type, MethodHandle mh, Object argument, int argnum) {
+ super(type);
if (mh.type().parameterType(argnum).isPrimitive())
this.argument = bindPrimitiveArgument(argument, mh, argnum);
else {
@@ -89,18 +77,14 @@ public class BoundMethodHandle extends MethodHandle {
}
private void initTarget(MethodHandle mh, int argnum) {
- if (MethodHandleNatives.JVM_SUPPORT) {
- this.vmtarget = null; // maybe updated by JVM
- MethodHandleNatives.init(this, mh, argnum);
- } else {
- this.vmtarget = mh;
- }
+ //this.vmtarget = mh; // maybe updated by JVM
+ MethodHandleNatives.init(this, mh, argnum);
}
/** For the AdapterMethodHandle subclass.
*/
- BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
- super(Access.TOKEN, type);
+ /*non-public*/ BoundMethodHandle(MethodType type, Object argument, int vmargslot) {
+ super(type);
this.argument = argument;
this.vmargslot = vmargslot;
assert(this instanceof AdapterMethodHandle);
@@ -112,8 +96,8 @@ public class BoundMethodHandle extends MethodHandle {
* same as {@code entryPoint}, except that the first argument
* type will be dropped.
*/
- protected BoundMethodHandle(Access token, MethodHandle entryPoint) {
- super(token, entryPoint.type().dropParameterTypes(0, 1));
+ /*non-public*/ BoundMethodHandle(MethodHandle entryPoint) {
+ super(entryPoint.type().dropParameterTypes(0, 1));
this.argument = this; // kludge; get rid of
this.vmargslot = this.type().parameterSlotDepth(0);
initTarget(entryPoint, 0);
@@ -172,7 +156,7 @@ public class BoundMethodHandle extends MethodHandle {
@Override
public String toString() {
- return MethodHandleImpl.addTypeString(baseName(), this);
+ return addTypeString(baseName(), this);
}
/** Component of toString() before the type string. */
diff --git a/jdk/src/share/classes/java/dyn/CallSite.java b/jdk/src/share/classes/java/lang/invoke/CallSite.java
similarity index 75%
rename from jdk/src/share/classes/java/dyn/CallSite.java
rename to jdk/src/share/classes/java/lang/invoke/CallSite.java
index 42af08a729b..b2da146d261 100644
--- a/jdk/src/share/classes/java/dyn/CallSite.java
+++ b/jdk/src/share/classes/java/lang/invoke/CallSite.java
@@ -23,12 +23,12 @@
* questions.
*/
-package java.dyn;
+package java.lang.invoke;
-import sun.dyn.*;
-import sun.dyn.empty.Empty;
+import sun.invoke.empty.Empty;
import sun.misc.Unsafe;
-import java.util.Collection;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* A {@code CallSite} is a holder for a variable {@link MethodHandle},
@@ -85,7 +85,6 @@ private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String nam
*/
abstract
public class CallSite {
- private static final Access IMPL_TOKEN = Access.getToken();
static { MethodHandleImpl.initStatics(); }
// Fields used only by the JVM. Do not use or change.
@@ -96,9 +95,6 @@ public class CallSite {
/*package-private*/
MethodHandle target;
- // Remove this field for PFD and delete deprecated methods:
- private MemberName calleeNameRemoveForPFD;
-
/**
* Make a blank call site object with the given method type.
* An initial target method is supplied which will throw
@@ -111,7 +107,7 @@ public class CallSite {
*/
/*package-private*/
CallSite(MethodType type) {
- target = MethodHandles.invokers(type).uninitializedCallSite();
+ target = type.invokers().uninitializedCallSite();
}
/**
@@ -145,7 +141,7 @@ public class CallSite {
int callerBCI) {
if (this.vmmethod != null) {
// FIXME
- throw new InvokeDynamicBootstrapError("call site has already been linked to an invokedynamic instruction");
+ throw new BootstrapMethodError("call site has already been linked to an invokedynamic instruction");
}
if (!this.type().equals(type)) {
throw wrongTargetType(target, type);
@@ -202,7 +198,7 @@ public class CallSite {
}
/**
- * Produce a method handle equivalent to an invokedynamic instruction
+ * Produces a method handle equivalent to an invokedynamic instruction
* which has been linked to this call site.
*
* This method is equivalent to the following code:
@@ -218,7 +214,7 @@ public class CallSite {
public abstract MethodHandle dynamicInvoker();
/*non-public*/ MethodHandle makeDynamicInvoker() {
- MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this);
+ MethodHandle getTarget = MethodHandleImpl.bindReceiver(GET_TARGET, this);
MethodHandle invoker = MethodHandles.exactInvoker(this.type());
return MethodHandles.foldArguments(invoker, getTarget);
}
@@ -226,7 +222,7 @@ public class CallSite {
private static final MethodHandle GET_TARGET;
static {
try {
- GET_TARGET = MethodHandles.Lookup.IMPL_LOOKUP.
+ GET_TARGET = IMPL_LOOKUP.
findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
} catch (ReflectiveOperationException ignore) {
throw new InternalError();
@@ -252,7 +248,6 @@ public class CallSite {
/*package-private*/
void setTargetNormal(MethodHandle newTarget) {
target = newTarget;
- //CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
}
/*package-private*/
MethodHandle getTargetVolatile() {
@@ -261,6 +256,68 @@ public class CallSite {
/*package-private*/
void setTargetVolatile(MethodHandle newTarget) {
unsafe.putObjectVolatile(this, TARGET_OFFSET, newTarget);
- //CallSiteImpl.setCallSiteTarget(IMPL_TOKEN, this, newTarget);
+ }
+
+ // this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
+ static CallSite makeSite(MethodHandle bootstrapMethod,
+ // Callee information:
+ String name, MethodType type,
+ // Extra arguments for BSM, if any:
+ Object info,
+ // Caller information:
+ MemberName callerMethod, int callerBCI) {
+ Class> callerClass = callerMethod.getDeclaringClass();
+ Object caller = IMPL_LOOKUP.in(callerClass);
+ CallSite site;
+ try {
+ Object binding;
+ info = maybeReBox(info);
+ if (info == null) {
+ binding = bootstrapMethod.invokeGeneric(caller, name, type);
+ } else if (!info.getClass().isArray()) {
+ binding = bootstrapMethod.invokeGeneric(caller, name, type, info);
+ } else {
+ Object[] argv = (Object[]) info;
+ maybeReBoxElements(argv);
+ if (3 + argv.length > 255)
+ throw new BootstrapMethodError("too many bootstrap method arguments");
+ MethodType bsmType = bootstrapMethod.type();
+ if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class)
+ binding = bootstrapMethod.invokeGeneric(caller, name, type, argv);
+ else
+ binding = MethodHandles.spreadInvoker(bsmType, 3)
+ .invokeGeneric(bootstrapMethod, caller, name, type, argv);
+ }
+ //System.out.println("BSM for "+name+type+" => "+binding);
+ if (binding instanceof CallSite) {
+ site = (CallSite) binding;
+ } else {
+ throw new ClassCastException("bootstrap method failed to produce a CallSite");
+ }
+ assert(site.getTarget() != null);
+ assert(site.getTarget().type().equals(type));
+ } catch (Throwable ex) {
+ BootstrapMethodError bex;
+ if (ex instanceof BootstrapMethodError)
+ bex = (BootstrapMethodError) ex;
+ else
+ bex = new BootstrapMethodError("call site initialization exception", ex);
+ throw bex;
+ }
+ return site;
+ }
+
+ private static Object maybeReBox(Object x) {
+ if (x instanceof Integer) {
+ int xi = (int) x;
+ if (xi == (byte) xi)
+ x = xi; // must rebox; see JLS 5.1.7
+ }
+ return x;
+ }
+ private static void maybeReBoxElements(Object[] xa) {
+ for (int i = 0; i < xa.length; i++) {
+ xa[i] = maybeReBox(xa[i]);
+ }
}
}
diff --git a/jdk/src/share/classes/java/dyn/ConstantCallSite.java b/jdk/src/share/classes/java/lang/invoke/ConstantCallSite.java
similarity index 99%
rename from jdk/src/share/classes/java/dyn/ConstantCallSite.java
rename to jdk/src/share/classes/java/lang/invoke/ConstantCallSite.java
index 50240a0f50f..e182c54aaa9 100644
--- a/jdk/src/share/classes/java/dyn/ConstantCallSite.java
+++ b/jdk/src/share/classes/java/lang/invoke/ConstantCallSite.java
@@ -23,7 +23,7 @@
* questions.
*/
-package java.dyn;
+package java.lang.invoke;
/**
* A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
diff --git a/jdk/src/share/classes/sun/dyn/DirectMethodHandle.java b/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java
similarity index 91%
rename from jdk/src/share/classes/sun/dyn/DirectMethodHandle.java
rename to jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java
index b43f353bbd6..13bedb17859 100644
--- a/jdk/src/share/classes/sun/dyn/DirectMethodHandle.java
+++ b/jdk/src/share/classes/java/lang/invoke/DirectMethodHandle.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,10 +23,9 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
-import static sun.dyn.MethodHandleNatives.Constants.*;
+import static java.lang.invoke.MethodHandleNatives.Constants.*;
/**
* The flavor of method handle which emulates invokespecial or invokestatic.
@@ -39,7 +38,7 @@ class DirectMethodHandle extends MethodHandle {
// Constructors in this class *must* be package scoped or private.
DirectMethodHandle(MethodType mtype, MemberName m, boolean doDispatch, Class> lookupClass) {
- super(Access.TOKEN, mtype);
+ super(mtype);
assert(m.isMethod() || !doDispatch && m.isConstructor());
if (!m.isResolved())
diff --git a/jdk/src/share/classes/sun/dyn/FilterGeneric.java b/jdk/src/share/classes/java/lang/invoke/FilterGeneric.java
similarity index 99%
rename from jdk/src/share/classes/sun/dyn/FilterGeneric.java
rename to jdk/src/share/classes/java/lang/invoke/FilterGeneric.java
index e77d742a11e..6c3395002f5 100644
--- a/jdk/src/share/classes/sun/dyn/FilterGeneric.java
+++ b/jdk/src/share/classes/java/lang/invoke/FilterGeneric.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,11 +23,11 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
import java.lang.reflect.*;
-import static sun.dyn.MemberName.newIllegalArgumentException;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* These adapters apply arbitrary conversions to arguments
@@ -123,7 +123,7 @@ class FilterGeneric {
MethodType entryType = entryType(kind, pos, filterType, targetType);
if (entryType.generic() != entryType)
throw newIllegalArgumentException("must be generic: "+entryType);
- MethodTypeImpl form = MethodTypeImpl.of(entryType);
+ MethodTypeForm form = entryType.form();
FilterGeneric filterGen = form.filterGeneric;
if (filterGen == null)
form.filterGeneric = filterGen = new FilterGeneric(entryType);
@@ -186,7 +186,7 @@ class FilterGeneric {
// see if it has the required invoke method
MethodHandle entryPoint = null;
try {
- entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
+ entryPoint = IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
} catch (ReflectiveOperationException ex) {
}
if (entryPoint == null) continue;
@@ -231,7 +231,7 @@ class FilterGeneric {
@Override
public String toString() {
- return MethodHandleImpl.addTypeString(target, this);
+ return addTypeString(target, this);
}
protected boolean isPrototype() { return target == null; }
@@ -246,7 +246,7 @@ class FilterGeneric {
protected Adapter(MethodHandle entryPoint,
MethodHandle filter, MethodHandle target) {
- super(Access.TOKEN, entryPoint);
+ super(entryPoint);
this.filter = filter;
this.target = target;
}
@@ -256,7 +256,7 @@ class FilterGeneric {
MethodHandle filter, MethodHandle target);
// { return new ThisType(entryPoint, filter, target); }
- static private final String CLASS_PREFIX; // "sun.dyn.FilterGeneric$"
+ static private final String CLASS_PREFIX; // "java.lang.invoke.FilterGeneric$"
static {
String aname = Adapter.class.getName();
String sname = Adapter.class.getSimpleName();
diff --git a/jdk/src/share/classes/sun/dyn/FilterOneArgument.java b/jdk/src/share/classes/java/lang/invoke/FilterOneArgument.java
similarity index 86%
rename from jdk/src/share/classes/sun/dyn/FilterOneArgument.java
rename to jdk/src/share/classes/java/lang/invoke/FilterOneArgument.java
index 86c722f3c0a..64a9f072797 100644
--- a/jdk/src/share/classes/sun/dyn/FilterOneArgument.java
+++ b/jdk/src/share/classes/java/lang/invoke/FilterOneArgument.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,10 +23,10 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
-import static sun.dyn.MemberName.uncaughtException;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Unary function composition, useful for many small plumbing jobs.
@@ -36,7 +36,7 @@ import static sun.dyn.MemberName.uncaughtException;
* final method type is the responsibility of a JVM-level adapter.
* @author jrose
*/
-public class FilterOneArgument extends BoundMethodHandle {
+class FilterOneArgument extends BoundMethodHandle {
protected final MethodHandle filter; // Object -> Object
protected final MethodHandle target; // Object -> Object
@@ -54,15 +54,15 @@ public class FilterOneArgument extends BoundMethodHandle {
static {
try {
INVOKE =
- MethodHandleImpl.IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke",
- MethodType.genericMethodType(1));
+ IMPL_LOOKUP.findVirtual(FilterOneArgument.class, "invoke",
+ MethodType.genericMethodType(1));
} catch (ReflectiveOperationException ex) {
throw uncaughtException(ex);
}
}
protected FilterOneArgument(MethodHandle filter, MethodHandle target) {
- super(Access.TOKEN, INVOKE);
+ super(INVOKE);
this.filter = filter;
this.target = target;
}
diff --git a/jdk/src/share/classes/sun/dyn/FromGeneric.java b/jdk/src/share/classes/java/lang/invoke/FromGeneric.java
similarity index 97%
rename from jdk/src/share/classes/sun/dyn/FromGeneric.java
rename to jdk/src/share/classes/java/lang/invoke/FromGeneric.java
index b996a6b3ead..1c0523a4a36 100644
--- a/jdk/src/share/classes/sun/dyn/FromGeneric.java
+++ b/jdk/src/share/classes/java/lang/invoke/FromGeneric.java
@@ -23,12 +23,13 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
+import sun.invoke.util.ValueConversions;
+import sun.invoke.util.Wrapper;
import java.lang.reflect.*;
-import sun.dyn.util.*;
-import static sun.dyn.MethodTypeImpl.invokers;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Adapters which mediate between incoming calls which are generic
@@ -82,8 +83,8 @@ class FromGeneric {
}
// outgoing primitive arguments will be wrapped; unwrap them
- MethodType primsAsObj = MethodTypeImpl.of(targetType).primArgsAsBoxes();
- MethodType objArgsRawRet = MethodTypeImpl.of(primsAsObj).primsAsInts();
+ MethodType primsAsObj = targetType.form().primArgsAsBoxes();
+ MethodType objArgsRawRet = primsAsObj.form().primsAsInts();
if (objArgsRawRet != targetType)
ad = findAdapter(internalType0 = objArgsRawRet);
if (ad == null) {
@@ -129,16 +130,16 @@ class FromGeneric {
MethodType targetType, MethodType internalType) {
// All the adapters we have here have reference-untyped internal calls.
assert(internalType == internalType.erase());
- MethodHandle invoker = invokers(targetType).exactInvoker();
+ MethodHandle invoker = targetType.invokers().exactInvoker();
// cast all narrow reference types, unbox all primitive arguments:
MethodType fixArgsType = internalType.changeReturnType(targetType.returnType());
- MethodHandle fixArgs = AdapterMethodHandle.convertArguments(Access.TOKEN,
+ MethodHandle fixArgs = MethodHandleImpl.convertArguments(
invoker, Invokers.invokerType(fixArgsType),
invoker.type(), null);
if (fixArgs == null)
throw new InternalError("bad fixArgs");
// reinterpret the calling sequence as raw:
- MethodHandle retyper = AdapterMethodHandle.makeRetypeRaw(Access.TOKEN,
+ MethodHandle retyper = AdapterMethodHandle.makeRetypeRaw(
Invokers.invokerType(internalType), fixArgs);
if (retyper == null)
throw new InternalError("bad retyper");
@@ -171,7 +172,7 @@ class FromGeneric {
/** Return the adapter information for this type's erasure. */
static FromGeneric of(MethodType type) {
- MethodTypeImpl form = MethodTypeImpl.of(type);
+ MethodTypeForm form = type.form();
FromGeneric fromGen = form.fromGeneric;
if (fromGen == null)
form.fromGeneric = fromGen = new FromGeneric(form.erasedType());
@@ -185,7 +186,7 @@ class FromGeneric {
/* Create an adapter that handles spreading calls for the given type. */
static Adapter findAdapter(MethodType internalType) {
MethodType entryType = internalType.generic();
- MethodTypeImpl form = MethodTypeImpl.of(internalType);
+ MethodTypeForm form = internalType.form();
Class> rtype = internalType.returnType();
int argc = form.parameterCount();
int lac = form.longPrimitiveParameterCount();
@@ -203,7 +204,7 @@ class FromGeneric {
// see if it has the required invoke method
MethodHandle entryPoint = null;
try {
- entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
+ entryPoint = IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
} catch (ReflectiveOperationException ex) {
}
if (entryPoint == null) continue;
@@ -257,7 +258,7 @@ class FromGeneric {
@Override
public String toString() {
- return MethodHandleImpl.addTypeString(target, this);
+ return addTypeString(target, this);
}
protected boolean isPrototype() { return target == null; }
@@ -272,7 +273,7 @@ class FromGeneric {
protected Adapter(MethodHandle entryPoint,
MethodHandle invoker, MethodHandle convert, MethodHandle target) {
- super(Access.TOKEN, entryPoint);
+ super(entryPoint);
this.invoker = invoker;
this.convert = convert;
this.target = target;
@@ -290,7 +291,7 @@ class FromGeneric {
protected Object convert_F(float result) throws Throwable { return convert.invokeExact(result); }
protected Object convert_D(double result) throws Throwable { return convert.invokeExact(result); }
- static private final String CLASS_PREFIX; // "sun.dyn.FromGeneric$"
+ static private final String CLASS_PREFIX; // "java.lang.invoke.FromGeneric$"
static {
String aname = Adapter.class.getName();
String sname = Adapter.class.getSimpleName();
diff --git a/jdk/src/share/classes/java/dyn/InvokeDynamic.java b/jdk/src/share/classes/java/lang/invoke/InvokeDynamic.java
similarity index 93%
rename from jdk/src/share/classes/java/dyn/InvokeDynamic.java
rename to jdk/src/share/classes/java/lang/invoke/InvokeDynamic.java
index 9c3ede1ee36..4668d741bbb 100644
--- a/jdk/src/share/classes/java/dyn/InvokeDynamic.java
+++ b/jdk/src/share/classes/java/lang/invoke/InvokeDynamic.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,7 +23,7 @@
* questions.
*/
-package java.dyn;
+package java.lang.invoke;
/**
* This is a place-holder class. Some HotSpot implementations need to see it.
diff --git a/jdk/src/share/classes/sun/dyn/InvokeGeneric.java b/jdk/src/share/classes/java/lang/invoke/InvokeGeneric.java
similarity index 86%
rename from jdk/src/share/classes/sun/dyn/InvokeGeneric.java
rename to jdk/src/share/classes/java/lang/invoke/InvokeGeneric.java
index 0d1a5defce3..a235e7318da 100644
--- a/jdk/src/share/classes/sun/dyn/InvokeGeneric.java
+++ b/jdk/src/share/classes/java/lang/invoke/InvokeGeneric.java
@@ -23,15 +23,13 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
-import java.lang.reflect.*;
-import sun.dyn.util.*;
-import static sun.dyn.MethodTypeImpl.invokers;
+import sun.invoke.util.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
- * Adapters which manage MethodHanndle.invokeGeneric calls.
+ * Adapters which manage MethodHandle.invokeGeneric calls.
* The JVM calls one of these when the exact type match fails.
* @author jrose
*/
@@ -44,7 +42,8 @@ class InvokeGeneric {
/** Compute and cache information for this adapter, so that it can
* call out to targets of the erasure-family of the given erased type.
*/
- private InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException {
+ /*non-public*/ InvokeGeneric(MethodType erasedCallerType) throws ReflectiveOperationException {
+ assert(erasedCallerType.equals(erasedCallerType.erase()));
this.erasedCallerType = erasedCallerType;
this.initialInvoker = makeInitialInvoker();
assert initialInvoker.type().equals(erasedCallerType
@@ -53,22 +52,13 @@ class InvokeGeneric {
}
private static MethodHandles.Lookup lookup() {
- return MethodHandleImpl.IMPL_LOOKUP;
+ return IMPL_LOOKUP;
}
/** Return the adapter information for this type's erasure. */
- static MethodHandle genericInvokerOf(MethodType type) {
- MethodTypeImpl form = MethodTypeImpl.of(type);
- MethodHandle genericInvoker = form.genericInvoker;
- if (genericInvoker == null) {
- try {
- InvokeGeneric gen = new InvokeGeneric(form.erasedType());
- form.genericInvoker = genericInvoker = gen.initialInvoker;
- } catch (ReflectiveOperationException ex) {
- throw new RuntimeException(ex);
- }
- }
- return genericInvoker;
+ /*non-public*/ static MethodHandle genericInvokerOf(MethodType erasedCallerType) throws ReflectiveOperationException {
+ InvokeGeneric gen = new InvokeGeneric(erasedCallerType);
+ return gen.initialInvoker;
}
private MethodHandle makeInitialInvoker() throws ReflectiveOperationException {
@@ -88,7 +78,7 @@ class InvokeGeneric {
private MethodHandle makePostDispatchInvoker() {
// Take (MH'; MT, MH; A...) and run MH'(MT, MH; A...).
MethodType invokerType = erasedCallerType.insertParameterTypes(0, EXTRA_ARGS);
- return invokers(invokerType).exactInvoker();
+ return invokerType.invokers().exactInvoker();
}
private MethodHandle dropDispatchArguments(MethodHandle targetInvoker) {
assert(targetInvoker.type().parameterType(0) == MethodHandle.class);
@@ -112,7 +102,7 @@ class InvokeGeneric {
if (USE_AS_TYPE_PATH || target.isVarargsCollector()) {
MethodHandle newTarget = target.asType(callerType);
targetType = callerType;
- Invokers invokers = MethodTypeImpl.invokers(Access.TOKEN, targetType);
+ Invokers invokers = targetType.invokers();
MethodHandle invoker = invokers.erasedInvokerWithDrops;
if (invoker == null) {
invokers.erasedInvokerWithDrops = invoker =
diff --git a/jdk/src/share/classes/sun/dyn/Invokers.java b/jdk/src/share/classes/java/lang/invoke/Invokers.java
similarity index 87%
rename from jdk/src/share/classes/sun/dyn/Invokers.java
rename to jdk/src/share/classes/java/lang/invoke/Invokers.java
index 55eef1911ba..4eeb36f76b7 100644
--- a/jdk/src/share/classes/sun/dyn/Invokers.java
+++ b/jdk/src/share/classes/java/lang/invoke/Invokers.java
@@ -23,16 +23,16 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
-import sun.dyn.empty.Empty;
+import sun.invoke.empty.Empty;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Construction and caching of often-used invokers.
* @author jrose
*/
-public class Invokers {
+class Invokers {
// exact type (sans leading taget MH) for the outgoing call
private final MethodType targetType;
@@ -60,15 +60,15 @@ public class Invokers {
this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1];
}
- public static MethodType invokerType(MethodType targetType) {
+ /*non-public*/ static MethodType invokerType(MethodType targetType) {
return targetType.insertParameterTypes(0, MethodHandle.class);
}
- public MethodHandle exactInvoker() {
+ /*non-public*/ MethodHandle exactInvoker() {
MethodHandle invoker = exactInvoker;
if (invoker != null) return invoker;
try {
- invoker = MethodHandleImpl.IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType);
+ invoker = IMPL_LOOKUP.findVirtual(MethodHandle.class, "invokeExact", targetType);
} catch (ReflectiveOperationException ex) {
throw new InternalError("JVM cannot find invoker for "+targetType);
}
@@ -77,7 +77,7 @@ public class Invokers {
return invoker;
}
- public MethodHandle genericInvoker() {
+ /*non-public*/ MethodHandle genericInvoker() {
MethodHandle invoker1 = exactInvoker();
MethodHandle invoker = genericInvoker;
if (invoker != null) return invoker;
@@ -87,7 +87,7 @@ public class Invokers {
return invoker;
}
- public MethodHandle erasedInvoker() {
+ /*non-public*/ MethodHandle erasedInvoker() {
MethodHandle invoker1 = exactInvoker();
MethodHandle invoker = erasedInvoker;
if (invoker != null) return invoker;
@@ -100,7 +100,7 @@ public class Invokers {
return invoker;
}
- public MethodHandle spreadInvoker(int objectArgCount) {
+ /*non-public*/ MethodHandle spreadInvoker(int objectArgCount) {
MethodHandle vaInvoker = spreadInvokers[objectArgCount];
if (vaInvoker != null) return vaInvoker;
MethodHandle gInvoker = genericInvoker();
@@ -111,12 +111,12 @@ public class Invokers {
private static MethodHandle THROW_UCS = null;
- public MethodHandle uninitializedCallSite() {
+ /*non-public*/ MethodHandle uninitializedCallSite() {
MethodHandle invoker = uninitializedCallSite;
if (invoker != null) return invoker;
if (targetType.parameterCount() > 0) {
MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount());
- Invokers invokers0 = MethodTypeImpl.invokers(type0);
+ Invokers invokers0 = type0.invokers();
invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(),
0, targetType.parameterList());
assert(invoker.type().equals(targetType));
@@ -125,14 +125,14 @@ public class Invokers {
}
if (THROW_UCS == null) {
try {
- THROW_UCS = MethodHandleImpl.IMPL_LOOKUP
+ THROW_UCS = IMPL_LOOKUP
.findStatic(CallSite.class, "uninitializedCallSite",
MethodType.methodType(Empty.class));
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
}
- invoker = AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, targetType, THROW_UCS);
+ invoker = AdapterMethodHandle.makeRetypeRaw(targetType, THROW_UCS);
assert(invoker.type().equals(targetType));
uninitializedCallSite = invoker;
return invoker;
diff --git a/jdk/src/share/classes/sun/dyn/MemberName.java b/jdk/src/share/classes/java/lang/invoke/MemberName.java
similarity index 93%
rename from jdk/src/share/classes/sun/dyn/MemberName.java
rename to jdk/src/share/classes/java/lang/invoke/MemberName.java
index 5e98b85ca60..0300fe758cc 100644
--- a/jdk/src/share/classes/sun/dyn/MemberName.java
+++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java
@@ -23,10 +23,9 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import sun.dyn.util.BytecodeDescriptor;
-import java.dyn.*;
+import sun.invoke.util.BytecodeDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -37,7 +36,8 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
-import static sun.dyn.MethodHandleNatives.Constants.*;
+import static java.lang.invoke.MethodHandleNatives.Constants.*;
+import static java.lang.invoke.MethodHandleStatics.*;
/**
* A {@code MemberName} is a compact symbolic datum which fully characterizes
@@ -66,7 +66,7 @@ import static sun.dyn.MethodHandleNatives.Constants.*;
* and those seven fields omit much of the information in Method.
* @author jrose
*/
-public final class MemberName implements Member, Cloneable {
+/*non-public*/ final class MemberName implements Member, Cloneable {
private Class> clazz; // class in which the method is defined
private String name; // may be null if not yet materialized
private Object type; // may be null if not yet materialized
@@ -435,7 +435,7 @@ public final class MemberName implements Member, Cloneable {
/** Query whether this member name is resolved to a non-static, non-final method.
*/
public boolean hasReceiverTypeDispatch() {
- return (isMethod() && getVMIndex(Access.TOKEN) >= 0);
+ return (isMethod() && getVMIndex() >= 0);
}
/** Produce a string form of this member name.
@@ -490,59 +490,38 @@ public final class MemberName implements Member, Cloneable {
// Queries to the JVM:
/** Document? */
- public int getVMIndex(Access token) {
- Access.check(token);
+ /*non-public*/ int getVMIndex() {
if (!isResolved())
- throw newIllegalStateException("not resolved");
+ throw newIllegalStateException("not resolved", this);
return vmindex;
}
-// public Object getVMTarget(Access token) {
-// Access.check(token);
+// /*non-public*/ Object getVMTarget() {
// if (!isResolved())
-// throw newIllegalStateException("not resolved");
+// throw newIllegalStateException("not resolved", this);
// return vmtarget;
// }
- private RuntimeException newIllegalStateException(String message) {
- return new IllegalStateException(message+": "+this);
- }
- // handy shared exception makers (they simplify the common case code)
- public static RuntimeException newIllegalArgumentException(String message) {
- return new IllegalArgumentException(message);
- }
- public static IllegalAccessException newNoAccessException(MemberName name, Object from) {
- return newNoAccessException("cannot access", name, from);
- }
- public static IllegalAccessException newNoAccessException(String message,
- MemberName name, Object from) {
- message += ": " + name;
+ public IllegalAccessException makeAccessException(String message, Object from) {
+ message = message + ": "+ toString();
if (from != null) message += ", from " + from;
return new IllegalAccessException(message);
}
- public static ReflectiveOperationException newNoAccessException(MemberName name) {
- if (name.isResolved())
- return new IllegalAccessException(name.toString());
- else if (name.isConstructor())
- return new NoSuchMethodException(name.toString());
- else if (name.isMethod())
- return new NoSuchMethodException(name.toString());
+ public ReflectiveOperationException makeAccessException(String message) {
+ message = message + ": "+ toString();
+ if (isResolved())
+ return new IllegalAccessException(message);
+ else if (isConstructor())
+ return new NoSuchMethodException(message);
+ else if (isMethod())
+ return new NoSuchMethodException(message);
else
- return new NoSuchFieldException(name.toString());
- }
- public static Error uncaughtException(Exception ex) {
- Error err = new InternalError("uncaught exception");
- err.initCause(ex);
- return err;
+ return new NoSuchFieldException(message);
}
/** Actually making a query requires an access check. */
- public static Factory getFactory(Access token) {
- Access.check(token);
+ /*non-public*/ static Factory getFactory() {
return Factory.INSTANCE;
}
- public static Factory getFactory() {
- return getFactory(Access.getToken());
- }
/** A factory type for resolving member names with the help of the VM.
* TBD: Define access-safe public constructors for this factory.
*/
@@ -662,7 +641,7 @@ public final class MemberName implements Member, Cloneable {
MemberName result = resolveOrNull(m, searchSupers, lookupClass);
if (result != null)
return result;
- ReflectiveOperationException ex = newNoAccessException(m);
+ ReflectiveOperationException ex = m.makeAccessException("no access");
if (ex instanceof IllegalAccessException) throw (IllegalAccessException) ex;
throw nsmClass.cast(ex);
}
diff --git a/jdk/src/share/classes/java/dyn/MethodHandle.java b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java
similarity index 88%
rename from jdk/src/share/classes/java/dyn/MethodHandle.java
rename to jdk/src/share/classes/java/lang/invoke/MethodHandle.java
index b78b4024805..8165915c7bb 100644
--- a/jdk/src/share/classes/java/dyn/MethodHandle.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java
@@ -23,15 +23,10 @@
* questions.
*/
-package java.dyn;
+package java.lang.invoke;
-//import sun.dyn.*;
-import sun.dyn.Access;
-import sun.dyn.MethodHandleImpl;
-
-import static java.dyn.MethodHandles.invokers; // package-private API
-import static sun.dyn.MemberName.newIllegalArgumentException; // utility
+import static java.lang.invoke.MethodHandleStatics.*;
/**
* A method handle is a typed, directly executable reference to an underlying method,
@@ -40,14 +35,8 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* These transformations are quite general, and include such patterns as
* {@linkplain #asType conversion},
* {@linkplain #bindTo insertion},
- * {@linkplain java.dyn.MethodHandles#dropArguments deletion},
- * and {@linkplain java.dyn.MethodHandles#filterArguments substitution}.
- *
- * Note: The super-class of MethodHandle is Object.
- * Any other super-class visible in the Reference Implementation
- * will be removed before the Proposed Final Draft.
- * Also, the final version will not include any public or
- * protected constructors.
+ * {@linkplain java.lang.invoke.MethodHandles#dropArguments deletion},
+ * and {@linkplain java.lang.invoke.MethodHandles#filterArguments substitution}.
*
*
Method handle contents
* Method handles are dynamically and strongly typed according to type descriptor.
@@ -56,7 +45,7 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* the method handle's own {@linkplain #type method type}.
*
* Every method handle reports its type via the {@link #type type} accessor.
- * This type descriptor is a {@link java.dyn.MethodType MethodType} object,
+ * This type descriptor is a {@link java.lang.invoke.MethodType MethodType} object,
* whose structure is a series of classes, one of which is
* the return type of the method (or {@code void.class} if none).
*
@@ -156,7 +145,7 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* This allows a more powerful negotiation of method type
* between caller and callee.
*
- * (Note: The adjusted method handle {@code M2} is not directly observable,
+ * (Note: The adjusted method handle {@code M2} is not directly observable,
* and implementations are therefore not required to materialize it.)
*
*
Invocation checking
@@ -204,11 +193,11 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
* Java code can create a method handle that directly accesses
* any method, constructor, or field that is accessible to that code.
* This is done via a reflective, capability-based API called
- * {@link java.dyn.MethodHandles.Lookup MethodHandles.Lookup}
+ * {@link java.lang.invoke.MethodHandles.Lookup MethodHandles.Lookup}
* For example, a static method handle can be obtained
- * from {@link java.dyn.MethodHandles.Lookup#findStatic Lookup.findStatic}.
+ * from {@link java.lang.invoke.MethodHandles.Lookup#findStatic Lookup.findStatic}.
* There are also conversion methods from Core Reflection API objects,
- * such as {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect}.
+ * such as {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
*
* Like classes and strings, method handles that correspond to accessible
* fields, methods, and constructors can also be represented directly
@@ -269,7 +258,7 @@ mh = mh.asType(mt);
x = mh.invokeExact((Object)1, (Object)2, (Object)3);
// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
assert(x.equals(java.util.Arrays.asList(1,2,3)));
-// mt is { => int}
+// mt is int()
mt = MethodType.methodType(int.class);
mh = lookup.findVirtual(java.util.List.class, "size", mt);
i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
@@ -325,15 +314,15 @@ mh.invokeExact(System.out, "Hello, world.");
*
* For the sake of tools (but not as a programming API), the signature polymorphic
* methods are marked with a private yet standard annotation,
- * {@code @java.dyn.MethodHandle.PolymorphicSignature}.
+ * {@code @java.lang.invoke.MethodHandle.PolymorphicSignature}.
* The annotation's retention is {@code RUNTIME}, so that all tools can see it.
*
*
Formal rules for processing signature polymorphic methods
*
* The following methods (and no others) are signature polymorphic:
*
- * {@link java.dyn.MethodHandle#invokeExact MethodHandle.invokeExact}
- * {@link java.dyn.MethodHandle#invokeGeneric MethodHandle.invokeGeneric}
+ * {@link java.lang.invoke.MethodHandle#invokeExact MethodHandle.invokeExact}
+ * {@link java.lang.invoke.MethodHandle#invokeGeneric MethodHandle.invokeGeneric}
*
*
* A signature polymorphic method will be declared with the following properties:
@@ -341,7 +330,7 @@ mh.invokeExact(System.out, "Hello, world.");
*
It must be native.
* It must take a single varargs parameter of the form {@code Object...}.
* It must produce a return value of type {@code Object}.
- * It must be contained within the {@code java.dyn} package.
+ * It must be contained within the {@code java.lang.invoke} package.
*
* Because of these requirements, a signature polymorphic method is able to accept
* any number and type of actual arguments, and can, with a cast, produce a value of any type.
@@ -354,7 +343,7 @@ mh.invokeExact(System.out, "Hello, world.");
*
* In an argument position of a method invocation on a signature polymorphic method,
* a null literal has type {@code java.lang.Void}, unless cast to a reference type.
- * (Note: This typing rule allows the null type to have its own encoding in linkage information
+ * (Note: This typing rule allows the null type to have its own encoding in linkage information
* distinct from other types.
*
* The linkage information for the return type is derived from a context-dependent target typing convention.
@@ -374,12 +363,12 @@ mh.invokeExact(System.out, "Hello, world.");
* and without implicit boxing or unboxing.
*
*
Interoperation between method handles and the Core Reflection API
- * Using factory methods in the {@link java.dyn.MethodHandles.Lookup Lookup} API,
+ * Using factory methods in the {@link java.lang.invoke.MethodHandles.Lookup Lookup} API,
* any class member represented by a Core Reflection API object
* can be converted to a behaviorally equivalent method handle.
* For example, a reflective {@link java.lang.reflect.Method Method} can
* be converted to a method handle using
- * {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect}.
+ * {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
* The resulting method handles generally provide more direct and efficient
* access to the underlying class members.
*
@@ -398,9 +387,9 @@ mh.invokeExact(System.out, "Hello, world.");
* they will throw {@code UnsupportedOperationException}.
*
* In order to obtain an invoker method for a particular type descriptor,
- * use {@link java.dyn.MethodHandles#exactInvoker MethodHandles.exactInvoker},
- * or {@link java.dyn.MethodHandles#genericInvoker MethodHandles.genericInvoker}.
- * The {@link java.dyn.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
+ * use {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker},
+ * or {@link java.lang.invoke.MethodHandles#genericInvoker MethodHandles.genericInvoker}.
+ * The {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
* API is also able to return a method handle
* to call {@code invokeExact} or {@code invokeGeneric},
* for any specified type descriptor .
@@ -436,12 +425,35 @@ mh.invokeExact(System.out, "Hello, world.");
* @see MethodHandles
* @author John Rose, JSR 292 EG
*/
-public abstract class MethodHandle
- // Note: This is an implementation inheritance hack, and will be removed
- // with a JVM change which moves the required hidden state onto this class.
- extends MethodHandleImpl
-{
- private static Access IMPL_TOKEN = Access.getToken();
+public abstract class MethodHandle {
+ // { JVM internals:
+
+ private byte vmentry; // adapter stub or method entry point
+ //private int vmslots; // optionally, hoist type.form.vmslots
+ /*non-public*/ Object vmtarget; // VM-specific, class-specific target value
+
+ // TO DO: vmtarget should be invisible to Java, since the JVM puts internal
+ // managed pointers into it. Making it visible exposes it to debuggers,
+ // which can cause errors when they treat the pointer as an Object.
+
+ // These two dummy fields are present to force 'I' and 'J' signatures
+ // into this class's constant pool, so they can be transferred
+ // to vmentry when this class is loaded.
+ static final int INT_FIELD = 0;
+ static final long LONG_FIELD = 0;
+
+ // vmentry (a void* field) is used *only* by the JVM.
+ // The JVM adjusts its type to int or long depending on system wordsize.
+ // Since it is statically typed as neither int nor long, it is impossible
+ // to use this field from Java bytecode. (Please don't try to, either.)
+
+ // The vmentry is an assembly-language stub which is jumped to
+ // immediately after the method type is verified.
+ // For a direct MH, this stub loads the vmtarget's entry point
+ // and jumps to it.
+
+ // } End of JVM internals.
+
static { MethodHandleImpl.initStatics(); }
// interface MethodHandle
@@ -458,7 +470,7 @@ public abstract class MethodHandle
private MethodType type;
/**
- * Report the type of this method handle.
+ * Reports the type of this method handle.
* Every invocation of this method handle via {@code invokeExact} must exactly match this type.
* @return the method handle type
*/
@@ -467,39 +479,18 @@ public abstract class MethodHandle
}
/**
- * CONSTRUCTOR WILL BE REMOVED FOR PFD:
- * Temporary constructor in early versions of the Reference Implementation.
- * Method handle inheritance (if any) will be contained completely within
- * the {@code java.dyn} package.
+ * Package-private constructor for the method handle implementation hierarchy.
+ * Method handle inheritance will be contained completely within
+ * the {@code java.lang.invoke} package.
*/
- // The constructor for MethodHandle may only be called by privileged code.
- // Subclasses may be in other packages, but must possess
- // a token which they obtained from MH with a security check.
- // @param token non-null object which proves access permission
// @param type type (permanently assigned) of the new method handle
- protected MethodHandle(Access token, MethodType type) {
- super(token);
- Access.check(token);
- this.type = type;
- }
-
- private void initType(MethodType type) {
+ /*non-public*/ MethodHandle(MethodType type) {
type.getClass(); // elicit NPE
- if (this.type != null) throw new InternalError();
this.type = type;
}
- static {
- // This hack allows the implementation package special access to
- // the internals of MethodHandle. In particular, the MTImpl has all sorts
- // of cached information useful to the implementation code.
- MethodHandleImpl.setMethodHandleFriend(IMPL_TOKEN, new MethodHandleImpl.MethodHandleFriend() {
- public void initType(MethodHandle mh, MethodType type) { mh.initType(type); }
- });
- }
-
/**
- * Invoke the method handle, allowing any caller type descriptor, but requiring an exact type match.
+ * Invokes the method handle, allowing any caller type descriptor, but requiring an exact type match.
* The type descriptor at the call site of {@code invokeExact} must
* exactly match this method handle's {@link #type type}.
* No conversions are allowed on arguments or return values.
@@ -508,7 +499,7 @@ public abstract class MethodHandle
* it will appear as a single native method, taking an object array and returning an object.
* If this native method is invoked directly via
* {@link java.lang.reflect.Method#invoke Method.invoke}, via JNI,
- * or indirectly via {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect},
+ * or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
* it will throw an {@code UnsupportedOperationException}.
* @throws WrongMethodTypeException if the target's type is not identical with the caller's type descriptor
* @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
@@ -516,7 +507,7 @@ public abstract class MethodHandle
public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
/**
- * Invoke the method handle, allowing any caller type descriptor,
+ * Invokes the method handle, allowing any caller type descriptor,
* and optionally performing conversions on arguments and return values.
*
* If the call site type descriptor exactly matches this method handle's {@link #type type},
@@ -542,7 +533,7 @@ public abstract class MethodHandle
* it will appear as a single native method, taking an object array and returning an object.
* If this native method is invoked directly via
* {@link java.lang.reflect.Method#invoke Method.invoke}, via JNI,
- * or indirectly via {@link java.dyn.MethodHandles.Lookup#unreflect Lookup.unreflect},
+ * or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
* it will throw an {@code UnsupportedOperationException}.
* @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's type descriptor
* @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails
@@ -551,7 +542,7 @@ public abstract class MethodHandle
public final native @PolymorphicSignature Object invokeGeneric(Object... args) throws Throwable;
/**
- * Perform a varargs invocation, passing the arguments in the given array
+ * Performs a varargs invocation, passing the arguments in the given array
* to the method handle, as if via {@link #invokeGeneric invokeGeneric} from a call site
* which mentions only the type {@code Object}, and whose arity is the length
* of the argument array.
@@ -608,7 +599,7 @@ public abstract class MethodHandle
return asType(MethodType.genericMethodType(argc)).invokeWithArguments(arguments);
}
if (argc <= 10) {
- MethodHandle invoker = invokers(type).genericInvoker();
+ MethodHandle invoker = type.invokers().genericInvoker();
switch (argc) {
case 0: return invoker.invokeExact(this);
case 1: return invoker.invokeExact(this,
@@ -647,17 +638,34 @@ public abstract class MethodHandle
}
// more than ten arguments get boxed in a varargs list:
- MethodHandle invoker = invokers(type).spreadInvoker(0);
+ MethodHandle invoker = type.invokers().spreadInvoker(0);
return invoker.invokeExact(this, arguments);
}
- /** Equivalent to {@code invokeWithArguments(arguments.toArray())}. */
+
+ /**
+ * Performs a varargs invocation, passing the arguments in the given array
+ * to the method handle, as if via {@link #invokeGeneric invokeGeneric} from a call site
+ * which mentions only the type {@code Object}, and whose arity is the length
+ * of the argument array.
+ *
+ * This method is also equivalent to the following code:
+ *
+ * {@link #invokeWithArguments(Object...) invokeWithArguments}(arguments.toArray())
+ *
+ *
+ * @param arguments the arguments to pass to the target
+ * @return the result returned by the target
+ * @throws ClassCastException if an argument cannot be converted by reference casting
+ * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments
+ * @throws Throwable anything thrown by the target method invocation
+ */
public Object invokeWithArguments(java.util.List> arguments) throws Throwable {
return invokeWithArguments(arguments.toArray());
}
/**
- * Produce an adapter method handle which adapts the type of the
- * current method handle to a new type
+ * Produces an adapter method handle which adapts the type of the
+ * current method handle to a new type.
* The resulting method handle is guaranteed to report a type
* which is equal to the desired new type.
*
@@ -685,7 +693,7 @@ public abstract class MethodHandle
}
/**
- * Make an adapter which accepts a trailing array argument
+ * Makes an adapter which accepts a trailing array argument
* and spreads its elements as positional arguments.
* The new method handle adapts, as its target ,
* the current method handle. The type of the adapter will be
@@ -733,7 +741,7 @@ public abstract class MethodHandle
}
/**
- * Make an adapter which accepts a given number of trailing
+ * Makes an adapter which accepts a given number of trailing
* positional arguments and collects them into an array argument.
* The new method handle adapts, as its target ,
* the current method handle. The type of the adapter will be
@@ -784,7 +792,7 @@ public abstract class MethodHandle
}
/**
- * Make a variable arity adapter which is able to accept
+ * Makes a variable arity adapter which is able to accept
* any number of trailing positional arguments and collect them
* into an array argument.
*
@@ -942,12 +950,12 @@ assert(failed);
}
/**
- * Determine if this method handle
+ * Determines if this method handle
* supports {@linkplain #asVarargsCollector variable arity} calls.
* Such method handles arise from the following sources:
*
* a call to {@linkplain #asVarargsCollector asVarargsCollector}
- * a call to a {@linkplain java.dyn.MethodHandles.Lookup lookup method}
+ * a call to a {@linkplain java.lang.invoke.MethodHandles.Lookup lookup method}
* which resolves to a variable arity Java method or constructor
* an {@code ldc} instruction of a {@code CONSTANT_MethodHandle}
* which resolves to a variable arity Java method or constructor
@@ -960,9 +968,9 @@ assert(failed);
}
/**
- * Bind a value {@code x} to the first argument of a method handle, without invoking it.
+ * Binds a value {@code x} to the first argument of a method handle, without invoking it.
* The new method handle adapts, as its target ,
- * to the current method handle.
+ * the current method handle by binding it to the given argument.
* The type of the bound handle will be
* the same as the type of the target, except that a single leading
* reference parameter will be omitted.
@@ -974,9 +982,12 @@ assert(failed);
*
* The reference {@code x} must be convertible to the first parameter
* type of the target.
+ *
+ * (Note: Because method handles are immutable, the target method handle
+ * retains its original type and behavior.)
* @param x the value to bind to the first argument of the target
- * @return a new method handle which collects some trailing argument
- * into an array, before calling the original method handle
+ * @return a new method handle which prepends the given value to the incoming
+ * argument list, before calling the original method handle
* @throws IllegalArgumentException if the target does not have a
* leading parameter type that is a reference type
* @throws ClassCastException if {@code x} cannot be converted
@@ -984,7 +995,15 @@ assert(failed);
* @see MethodHandles#insertArguments
*/
public MethodHandle bindTo(Object x) {
- return MethodHandles.insertArguments(this, 0, x);
+ Class> ptype;
+ if (type().parameterCount() == 0 ||
+ (ptype = type().parameterType(0)).isPrimitive())
+ throw newIllegalArgumentException("no leading reference parameter", x);
+ x = MethodHandles.checkValue(ptype, x);
+ // Cf. MethodHandles.insertArguments for the following logic:
+ MethodHandle bmh = MethodHandleImpl.bindReceiver(this, x);
+ if (bmh != null) return bmh;
+ return MethodHandleImpl.bindArgument(this, 0, x);
}
/**
@@ -996,14 +1015,14 @@ assert(failed);
* "MethodHandle" + type().toString()
*
*
- * Note: Future releases of this API may add further information
+ * (Note: Future releases of this API may add further information
* to the string representation.
- * Therefore, the present syntax should not be parsed by applications.
+ * Therefore, the present syntax should not be parsed by applications.)
*
* @return a string representation of the method handle
*/
@Override
public String toString() {
- return MethodHandleImpl.getNameString(IMPL_TOKEN, this);
+ return getNameString(this);
}
}
diff --git a/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
similarity index 78%
rename from jdk/src/share/classes/sun/dyn/MethodHandleImpl.java
rename to jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
index eab4923540e..e82442092fe 100644
--- a/jdk/src/share/classes/sun/dyn/MethodHandleImpl.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -23,136 +23,36 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
-import java.dyn.MethodHandles.Lookup;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import sun.dyn.util.VerifyType;
+import sun.invoke.util.VerifyType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
-import sun.dyn.empty.Empty;
-import sun.dyn.util.ValueConversions;
-import sun.dyn.util.Wrapper;
+import sun.invoke.empty.Empty;
+import sun.invoke.util.ValueConversions;
+import sun.invoke.util.Wrapper;
import sun.misc.Unsafe;
-import static sun.dyn.MemberName.newIllegalArgumentException;
-import static sun.dyn.MemberName.newNoAccessException;
-import static sun.dyn.MemberName.uncaughtException;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
- * Base class for method handles, containing JVM-specific fields and logic.
- * TO DO: It should not be a base class.
+ * Trusted implementation code for MethodHandle.
* @author jrose
*/
-public abstract class MethodHandleImpl {
-
- // Fields which really belong in MethodHandle:
- private byte vmentry; // adapter stub or method entry point
- //private int vmslots; // optionally, hoist type.form.vmslots
- protected Object vmtarget; // VM-specific, class-specific target value
- //MethodType type; // defined in MethodHandle
-
- // TO DO: vmtarget should be invisible to Java, since the JVM puts internal
- // managed pointers into it. Making it visible exposes it to debuggers,
- // which can cause errors when they treat the pointer as an Object.
-
- // These two dummy fields are present to force 'I' and 'J' signatures
- // into this class's constant pool, so they can be transferred
- // to vmentry when this class is loaded.
- static final int INT_FIELD = 0;
- static final long LONG_FIELD = 0;
-
- /** Access methods for the internals of MethodHandle, supplied to
- * MethodHandleImpl as a trusted agent.
- */
- static public interface MethodHandleFriend {
- void initType(MethodHandle mh, MethodType type);
- }
- public static void setMethodHandleFriend(Access token, MethodHandleFriend am) {
- Access.check(token);
- if (METHOD_HANDLE_FRIEND != null)
- throw new InternalError(); // just once
- METHOD_HANDLE_FRIEND = am;
- }
- static private MethodHandleFriend METHOD_HANDLE_FRIEND;
-
- // NOT public
- static void initType(MethodHandle mh, MethodType type) {
- METHOD_HANDLE_FRIEND.initType(mh, type);
- }
-
- // type is defined in java.dyn.MethodHandle, which is platform-independent
-
- // vmentry (a void* field) is used *only* by by the JVM.
- // The JVM adjusts its type to int or long depending on system wordsize.
- // Since it is statically typed as neither int nor long, it is impossible
- // to use this field from Java bytecode. (Please don't try to, either.)
-
- // The vmentry is an assembly-language stub which is jumped to
- // immediately after the method type is verified.
- // For a direct MH, this stub loads the vmtarget's entry point
- // and jumps to it.
-
- /**
- * VM-based method handles must have a security token.
- * This security token can only be obtained by trusted code.
- * Do not create method handles directly; use factory methods.
- */
- public MethodHandleImpl(Access token) {
- Access.check(token);
- }
-
- /** Initialize the method type form to participate in JVM calls.
- * This is done once for each erased type.
- */
- public static void init(Access token, MethodType self) {
- Access.check(token);
- if (MethodHandleNatives.JVM_SUPPORT)
- MethodHandleNatives.init(self);
- }
-
+/*non-public*/ abstract class MethodHandleImpl {
/// Factory methods to create method handles:
private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
- static private Lookup IMPL_LOOKUP_INIT;
-
- public static void initLookup(Access token, Lookup lookup) {
- Access.check(token);
- if (IMPL_LOOKUP_INIT != null)
- throw new InternalError();
- IMPL_LOOKUP_INIT = lookup;
- }
-
- public static Lookup getLookup(Access token) {
- Access.check(token);
- return IMPL_LOOKUP;
- }
-
- static {
- if (!MethodHandleNatives.JVM_SUPPORT) // force init of native API
- throw new InternalError("No JVM support for JSR 292");
- // Force initialization of Lookup, so it calls us back as initLookup:
- MethodHandles.publicLookup();
- if (IMPL_LOOKUP_INIT == null)
- throw new InternalError();
- }
-
- public static void initStatics() {
+ static void initStatics() {
// Trigger preceding sequence.
}
- /** Shared secret with MethodHandles.Lookup, a copy of Lookup.IMPL_LOOKUP. */
- static final Lookup IMPL_LOOKUP = IMPL_LOOKUP_INIT;
-
-
/** Look up a given method.
- * Callable only from java.dyn and related packages.
+ * Callable only from sun.invoke and related packages.
*
* The resulting method handle type will be of the given type,
* with a receiver type {@code rcvc} prepended if the member is not static.
@@ -170,10 +70,9 @@ public abstract class MethodHandleImpl {
* @return a direct handle to the matching method
* @throws IllegalAccessException if the given method cannot be accessed by the lookup class
*/
- public static
- MethodHandle findMethod(Access token, MemberName method,
+ static
+ MethodHandle findMethod(MemberName method,
boolean doDispatch, Class> lookupClass) throws IllegalAccessException {
- Access.check(token); // only trusted calls
MethodType mtype = method.getMethodType();
if (!method.isStatic()) {
// adjust the advertised receiver type to be exactly the one requested
@@ -183,7 +82,7 @@ public abstract class MethodHandleImpl {
}
DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
if (!mh.isValid())
- throw newNoAccessException(method, lookupClass);
+ throw method.makeAccessException("no access", lookupClass);
assert(mh.type() == mtype);
if (!method.isVarargs())
return mh;
@@ -191,13 +90,12 @@ public abstract class MethodHandleImpl {
return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1));
}
- public static
- MethodHandle makeAllocator(Access token, MethodHandle rawConstructor) {
- Access.check(token);
+ static
+ MethodHandle makeAllocator(MethodHandle rawConstructor) {
MethodType rawConType = rawConstructor.type();
// Wrap the raw (unsafe) constructor with the allocation of a suitable object.
MethodHandle allocator
- = AllocateObject.make(token, rawConType.parameterType(0), rawConstructor);
+ = AllocateObject.make(rawConType.parameterType(0), rawConstructor);
assert(allocator.type()
.equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0))));
return allocator;
@@ -211,13 +109,11 @@ public abstract class MethodHandleImpl {
private AllocateObject(MethodHandle invoker,
Class allocateClass, MethodHandle rawConstructor) {
- super(Access.TOKEN, invoker);
+ super(invoker);
this.allocateClass = allocateClass;
this.rawConstructor = rawConstructor;
}
- static MethodHandle make(Access token,
- Class> allocateClass, MethodHandle rawConstructor) {
- Access.check(token);
+ static MethodHandle make(Class> allocateClass, MethodHandle rawConstructor) {
MethodType rawConType = rawConstructor.type();
assert(rawConType.parameterType(0) == allocateClass);
MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
@@ -225,18 +121,18 @@ public abstract class MethodHandleImpl {
if (nargs < INVOKES.length) {
MethodHandle invoke = INVOKES[nargs];
MethodType conType = CON_TYPES[nargs];
- MethodHandle gcon = convertArguments(token, rawConstructor, conType, rawConType, null);
+ MethodHandle gcon = convertArguments(rawConstructor, conType, rawConType, null);
if (gcon == null) return null;
MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
assert(galloc.type() == newType.generic());
- return convertArguments(token, galloc, newType, galloc.type(), null);
+ return convertArguments(galloc, newType, galloc.type(), null);
} else {
MethodHandle invoke = VARARGS_INVOKE;
MethodType conType = CON_TYPES[nargs];
- MethodHandle gcon = spreadArguments(token, rawConstructor, conType, 1);
+ MethodHandle gcon = spreadArguments(rawConstructor, conType, 1);
if (gcon == null) return null;
MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
- return collectArguments(token, galloc, newType, 1, null);
+ return collectArguments(galloc, newType, 1, null);
}
}
@Override
@@ -338,20 +234,16 @@ public abstract class MethodHandleImpl {
}
}
- public static
- MethodHandle accessField(Access token,
- MemberName member, boolean isSetter,
+ static
+ MethodHandle accessField(MemberName member, boolean isSetter,
Class> lookupClass) {
- Access.check(token);
// Use sun. misc.Unsafe to dig up the dirt on the field.
- MethodHandle mh = new FieldAccessor(token, member, isSetter);
+ MethodHandle mh = new FieldAccessor(member, isSetter);
return mh;
}
- public static
- MethodHandle accessArrayElement(Access token,
- Class> arrayClass, boolean isSetter) {
- Access.check(token);
+ static
+ MethodHandle accessArrayElement(Class> arrayClass, boolean isSetter) {
if (!arrayClass.isArray())
throw newIllegalArgumentException("not an array: "+arrayClass);
Class> elemClass = arrayClass.getComponentType();
@@ -379,12 +271,13 @@ public abstract class MethodHandleImpl {
final long offset;
final String name;
- public FieldAccessor(Access token, MemberName field, boolean isSetter) {
- super(Access.TOKEN, fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
- this.offset = (long) field.getVMIndex(token);
+ FieldAccessor(MemberName field, boolean isSetter) {
+ super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
+ this.offset = (long) field.getVMIndex();
this.name = field.getName();
this.base = staticBase(field);
}
+ @Override
public String toString() { return addTypeString(name, this); }
int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
@@ -560,10 +453,8 @@ public abstract class MethodHandleImpl {
* @param receiver Receiver (or first static method argument) to pre-bind.
* @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
*/
- public static
- MethodHandle bindReceiver(Access token,
- MethodHandle target, Object receiver) {
- Access.check(token);
+ static
+ MethodHandle bindReceiver(MethodHandle target, Object receiver) {
if (target instanceof AdapterMethodHandle &&
((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
) {
@@ -574,7 +465,7 @@ public abstract class MethodHandleImpl {
dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
MethodType newType = target.type().dropParameterTypes(0, 1);
- return convertArguments(token, bmh, newType, bmh.type(), null);
+ return convertArguments(bmh, newType, bmh.type(), null);
}
}
}
@@ -590,19 +481,15 @@ public abstract class MethodHandleImpl {
* @param receiver Argument (which can be a boxed primitive) to pre-bind.
* @return a suitable BoundMethodHandle
*/
- public static
- MethodHandle bindArgument(Access token,
- MethodHandle target, int argnum, Object receiver) {
- Access.check(token);
+ static
+ MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) {
return new BoundMethodHandle(target, receiver, argnum);
}
- public static MethodHandle convertArguments(Access token,
- MethodHandle target,
+ static MethodHandle convertArguments(MethodHandle target,
MethodType newType,
MethodType oldType,
int[] permutationOrNull) {
- Access.check(token);
assert(oldType.parameterCount() == target.type().parameterCount());
if (permutationOrNull != null) {
int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
@@ -613,7 +500,7 @@ public abstract class MethodHandleImpl {
for (int i = 0; i < outargs; i++)
callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
- target = convertArguments(token, target, callType, oldType, null);
+ target = convertArguments(target, callType, oldType, null);
assert(target != null);
oldType = target.type();
List goal = new ArrayList(); // i*TOKEN
@@ -710,7 +597,7 @@ public abstract class MethodHandleImpl {
Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
MethodHandle nextTarget
- = AdapterMethodHandle.makeRotateArguments(token, rotType, target,
+ = AdapterMethodHandle.makeRotateArguments(rotType, target,
rotBeg, rotSpan.size(), rotBy);
if (nextTarget != null) {
//System.out.println("Rot: "+rotSpan+" by "+rotBy);
@@ -733,7 +620,7 @@ public abstract class MethodHandleImpl {
int j = state.indexOf(arg);
Collections.swap(ptypes, i, j);
MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
- target = AdapterMethodHandle.makeSwapArguments(token, swapType, target, i, j);
+ target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
if (target == null) throw newIllegalArgumentException("cannot swap");
assert(target.type() == swapType);
oldType = swapType;
@@ -760,7 +647,7 @@ public abstract class MethodHandleImpl {
List> ptypes = oldType.parameterList();
ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
- target = AdapterMethodHandle.makeDupArguments(token, dupType, target, dupArgPos, dupArgCount);
+ target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
if (target == null)
throw newIllegalArgumentException("cannot dup");
oldType = target.type();
@@ -778,7 +665,7 @@ public abstract class MethodHandleImpl {
List> dropTypes = newType.parameterList()
.subList(dropArgPos, dropArgPos + dropArgCount);
MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
- target = AdapterMethodHandle.makeDropArguments(token, dropType, target, dropArgPos, dropArgCount);
+ target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
if (target == null) throw newIllegalArgumentException("cannot drop");
oldType = target.type();
}
@@ -787,7 +674,7 @@ public abstract class MethodHandleImpl {
return target;
if (oldType.parameterCount() != newType.parameterCount())
throw newIllegalArgumentException("mismatched parameter count");
- MethodHandle res = AdapterMethodHandle.makePairwiseConvert(token, newType, target);
+ MethodHandle res = AdapterMethodHandle.makePairwiseConvert(newType, target);
if (res != null)
return res;
int argc = oldType.parameterCount();
@@ -797,26 +684,24 @@ public abstract class MethodHandleImpl {
// then back to the desired types. We might have to use Java-based
// method handles to do this.
MethodType objType = MethodType.genericMethodType(argc);
- MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(token, objType, target);
+ MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(objType, target);
if (objTarget == null)
objTarget = FromGeneric.make(target);
- res = AdapterMethodHandle.makePairwiseConvert(token, newType, objTarget);
+ res = AdapterMethodHandle.makePairwiseConvert(newType, objTarget);
if (res != null)
return res;
return ToGeneric.make(newType, objTarget);
}
- public static MethodHandle spreadArguments(Access token,
- MethodHandle target,
+ static MethodHandle spreadArguments(MethodHandle target,
MethodType newType,
int spreadArg) {
- Access.check(token);
// TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
MethodType oldType = target.type();
// spread the last argument of newType to oldType
int spreadCount = oldType.parameterCount() - spreadArg;
Class spreadArgType = Object[].class;
- MethodHandle res = AdapterMethodHandle.makeSpreadArguments(token, newType, target, spreadArgType, spreadArg, spreadCount);
+ MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, spreadArgType, spreadArg, spreadCount);
if (res != null)
return res;
// try an intermediate adapter
@@ -829,20 +714,19 @@ public abstract class MethodHandleImpl {
ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
MethodType midType = MethodType.methodType(newType.returnType(), ptypes);
// after spreading, some arguments may need further conversion
- MethodHandle target2 = convertArguments(token, target, midType, oldType, null);
+ MethodHandle target2 = convertArguments(target, midType, oldType, null);
if (target2 == null)
throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType);
- res = AdapterMethodHandle.makeSpreadArguments(token, newType, target2, spreadArgType, spreadArg, spreadCount);
+ res = AdapterMethodHandle.makeSpreadArguments(newType, target2, spreadArgType, spreadArg, spreadCount);
if (res != null)
return res;
res = SpreadGeneric.make(target2, spreadCount);
if (res != null)
- res = convertArguments(token, res, newType, res.type(), null);
+ res = convertArguments(res, newType, res.type(), null);
return res;
}
- public static MethodHandle collectArguments(Access token,
- MethodHandle target,
+ static MethodHandle collectArguments(MethodHandle target,
MethodType newType,
int collectArg,
MethodHandle collector) {
@@ -856,29 +740,27 @@ public abstract class MethodHandleImpl {
// oldType // (a..., b...)=>r
assert(newType.parameterCount() == collectArg + colType.parameterCount());
assert(oldType.parameterCount() == collectArg + 1);
- MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null);
- MethodHandle gcollector = convertArguments(token, collector, colType.generic(), colType, null);
+ MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
+ MethodHandle gcollector = convertArguments(collector, colType.generic(), colType, null);
if (gtarget == null || gcollector == null) return null;
MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget);
- MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null);
+ MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
return result;
}
- public static MethodHandle filterArgument(Access token,
- MethodHandle target,
+ static MethodHandle filterArgument(MethodHandle target,
int pos,
MethodHandle filter) {
- Access.check(token);
MethodType ttype = target.type(), gttype = ttype.generic();
if (ttype != gttype) {
- target = convertArguments(token, target, gttype, ttype, null);
+ target = convertArguments(target, gttype, ttype, null);
ttype = gttype;
}
MethodType ftype = filter.type(), gftype = ftype.generic();
if (ftype.parameterCount() != 1)
throw new InternalError();
if (ftype != gftype) {
- filter = convertArguments(token, filter, gftype, ftype, null);
+ filter = convertArguments(filter, gftype, ftype, null);
ftype = gftype;
}
if (ftype == ttype) {
@@ -888,27 +770,24 @@ public abstract class MethodHandleImpl {
return FilterGeneric.makeArgumentFilter(pos, filter, target);
}
- public static MethodHandle foldArguments(Access token,
- MethodHandle target,
+ static MethodHandle foldArguments(MethodHandle target,
MethodType newType,
MethodHandle combiner) {
- Access.check(token);
MethodType oldType = target.type();
MethodType ctype = combiner.type();
- MethodHandle gtarget = convertArguments(token, target, oldType.generic(), oldType, null);
- MethodHandle gcombiner = convertArguments(token, combiner, ctype.generic(), ctype, null);
+ MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
+ MethodHandle gcombiner = convertArguments(combiner, ctype.generic(), ctype, null);
if (gtarget == null || gcombiner == null) return null;
MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget);
- MethodHandle result = convertArguments(token, gresult, newType, gresult.type(), null);
+ MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
return result;
}
- public static
- MethodHandle dropArguments(Access token, MethodHandle target,
+ static
+ MethodHandle dropArguments(MethodHandle target,
MethodType newType, int argnum) {
- Access.check(token);
int drops = newType.parameterCount() - target.type().parameterCount();
- MethodHandle res = AdapterMethodHandle.makeDropArguments(token, newType, target, argnum, drops);
+ MethodHandle res = AdapterMethodHandle.makeDropArguments(newType, target, argnum, drops);
if (res != null)
return res;
throw new UnsupportedOperationException("NYI");
@@ -918,36 +797,34 @@ public abstract class MethodHandleImpl {
private final MethodHandle test, target, fallback;
private GuardWithTest(MethodHandle invoker,
MethodHandle test, MethodHandle target, MethodHandle fallback) {
- super(Access.TOKEN, invoker);
+ super(invoker);
this.test = test;
this.target = target;
this.fallback = fallback;
}
- static MethodHandle make(Access token,
- MethodHandle test, MethodHandle target, MethodHandle fallback) {
- Access.check(token);
+ static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
MethodType type = target.type();
int nargs = type.parameterCount();
if (nargs < INVOKES.length) {
MethodHandle invoke = INVOKES[nargs];
MethodType gtype = type.generic();
assert(invoke.type().dropParameterTypes(0,1) == gtype);
- MethodHandle gtest = convertArguments(token, test, gtype.changeReturnType(boolean.class), test.type(), null);
- MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
- MethodHandle gfallback = convertArguments(token, fallback, gtype, type, null);
+ MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), null);
+ MethodHandle gtarget = convertArguments(target, gtype, type, null);
+ MethodHandle gfallback = convertArguments(fallback, gtype, type, null);
if (gtest == null || gtarget == null || gfallback == null) return null;
MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
- return convertArguments(token, gguard, type, gtype, null);
+ return convertArguments(gguard, type, gtype, null);
} else {
MethodHandle invoke = VARARGS_INVOKE;
MethodType gtype = MethodType.genericMethodType(1);
assert(invoke.type().dropParameterTypes(0,1) == gtype);
- MethodHandle gtest = spreadArguments(token, test, gtype.changeReturnType(boolean.class), 0);
- MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
- MethodHandle gfallback = spreadArguments(token, fallback, gtype, 0);
+ MethodHandle gtest = spreadArguments(test, gtype.changeReturnType(boolean.class), 0);
+ MethodHandle gtarget = spreadArguments(target, gtype, 0);
+ MethodHandle gfallback = spreadArguments(fallback, gtype, 0);
MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
if (gtest == null || gtarget == null || gfallback == null) return null;
- return collectArguments(token, gguard, type, 0, null);
+ return collectArguments(gguard, type, 0, null);
}
}
@Override
@@ -1034,24 +911,23 @@ public abstract class MethodHandleImpl {
}
}
- public static
- MethodHandle makeGuardWithTest(Access token,
- MethodHandle test,
+ static
+ MethodHandle makeGuardWithTest(MethodHandle test,
MethodHandle target,
MethodHandle fallback) {
- return GuardWithTest.make(token, test, target, fallback);
+ return GuardWithTest.make(test, target, fallback);
}
private static class GuardWithCatch extends BoundMethodHandle {
private final MethodHandle target;
private final Class extends Throwable> exType;
private final MethodHandle catcher;
- public GuardWithCatch(MethodHandle target, Class extends Throwable> exType, MethodHandle catcher) {
+ GuardWithCatch(MethodHandle target, Class extends Throwable> exType, MethodHandle catcher) {
this(INVOKES[target.type().parameterCount()], target, exType, catcher);
}
- public GuardWithCatch(MethodHandle invoker,
- MethodHandle target, Class extends Throwable> exType, MethodHandle catcher) {
- super(Access.TOKEN, invoker);
+ GuardWithCatch(MethodHandle invoker,
+ MethodHandle target, Class extends Throwable> exType, MethodHandle catcher) {
+ super(invoker);
this.target = target;
this.exType = exType;
this.catcher = catcher;
@@ -1171,42 +1047,40 @@ public abstract class MethodHandleImpl {
}
- public static
- MethodHandle makeGuardWithCatch(Access token,
- MethodHandle target,
+ static
+ MethodHandle makeGuardWithCatch(MethodHandle target,
Class extends Throwable> exType,
MethodHandle catcher) {
- Access.check(token);
MethodType type = target.type();
MethodType ctype = catcher.type();
int nargs = type.parameterCount();
if (nargs < GuardWithCatch.INVOKES.length) {
MethodType gtype = type.generic();
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
- MethodHandle gtarget = convertArguments(token, target, gtype, type, null);
- MethodHandle gcatcher = convertArguments(token, catcher, gcatchType, ctype, null);
+ MethodHandle gtarget = convertArguments(target, gtype, type, null);
+ MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, null);
MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
if (gtarget == null || gcatcher == null || gguard == null) return null;
- return convertArguments(token, gguard, type, gtype, null);
+ return convertArguments(gguard, type, gtype, null);
} else {
MethodType gtype = MethodType.genericMethodType(0, true);
MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
- MethodHandle gtarget = spreadArguments(token, target, gtype, 0);
- MethodHandle gcatcher = spreadArguments(token, catcher, gcatchType, 1);
+ MethodHandle gtarget = spreadArguments(target, gtype, 0);
+ MethodHandle gcatcher = spreadArguments(catcher, gcatchType, 1);
MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
if (gtarget == null || gcatcher == null || gguard == null) return null;
- return collectArguments(token, gguard, type, 0, null);
+ return collectArguments(gguard, type, 0, null);
}
}
- public static
- MethodHandle throwException(Access token, MethodType type) {
- Access.check(token);
- return AdapterMethodHandle.makeRetypeRaw(token, type, THROW_EXCEPTION);
+ static
+ MethodHandle throwException(MethodType type) {
+ return AdapterMethodHandle.makeRetypeRaw(type, throwException());
}
- static final MethodHandle THROW_EXCEPTION;
- static {
+ static MethodHandle THROW_EXCEPTION;
+ static MethodHandle throwException() {
+ if (THROW_EXCEPTION != null) return THROW_EXCEPTION;
try {
THROW_EXCEPTION
= IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
@@ -1214,71 +1088,19 @@ public abstract class MethodHandleImpl {
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
+ return THROW_EXCEPTION;
}
static Empty throwException(T t) throws T { throw t; }
- public static String getNameString(Access token, MethodHandle target, Object type) {
- Access.check(token);
- if (!(type instanceof MethodType)) {
- if (type == null)
- type = target.type();
- else if (type instanceof MethodHandle)
- type = ((MethodHandle)type).type();
- }
- MemberName name = null;
- if (target != null)
- name = MethodHandleNatives.getMethodName(target);
- if (name == null)
- return "invoke" + type;
- return name.getName() + type;
- }
-
- public static String getNameString(Access token, MethodHandle target) {
- return getNameString(token, target, null);
- }
-
- static String addTypeString(Object obj, MethodHandle target) {
- String str = String.valueOf(obj);
- if (target == null) return str;
- int paren = str.indexOf('(');
- if (paren >= 0) str = str.substring(0, paren);
- return str + target.type();
- }
-
- static void checkSpreadArgument(Object av, int n) {
- if (av == null ? n != 0 : ((Object[])av).length != n)
- throw newIllegalArgumentException("Array is not of length "+n);
- }
-
- static void raiseException(int code, Object actual, Object required) {
- String message;
- // disregard the identity of the actual object, if it is not a class:
- if (!(actual instanceof Class) && !(actual instanceof MethodType))
- actual = actual.getClass();
- if (actual != null)
- message = "required "+required+" but encountered "+actual;
- else
- message = "required "+required;
- switch (code) {
- case 192: // checkcast
- throw new ClassCastException(message);
- default:
- throw new InternalError("unexpected code "+code+": "+message);
- }
- }
-
// Linkage support:
- public static void registerBootstrap(Access token, Class> callerClass, MethodHandle bootstrapMethod) {
- Access.check(token);
+ static void registerBootstrap(Class> callerClass, MethodHandle bootstrapMethod) {
MethodHandleNatives.registerBootstrap(callerClass, bootstrapMethod);
}
- public static MethodHandle getBootstrap(Access token, Class> callerClass) {
- Access.check(token);
+ static MethodHandle getBootstrap(Class> callerClass) {
return MethodHandleNatives.getBootstrap(callerClass);
}
- public static MethodHandle asVarargsCollector(Access token, MethodHandle target, Class> arrayType) {
- Access.check(token);
- return AdapterMethodHandle.makeVarargsCollector(token, target, arrayType);
+ static MethodHandle asVarargsCollector(MethodHandle target, Class> arrayType) {
+ return AdapterMethodHandle.makeVarargsCollector(target, arrayType);
}
}
diff --git a/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
similarity index 89%
rename from jdk/src/share/classes/sun/dyn/MethodHandleNatives.java
rename to jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
index 5f1076bff6a..82d5d898638 100644
--- a/jdk/src/share/classes/sun/dyn/MethodHandleNatives.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,14 +23,13 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
-import java.dyn.MethodHandles.Lookup;
+import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
-import static sun.dyn.MethodHandleNatives.Constants.*;
-import static sun.dyn.MethodHandleImpl.IMPL_LOOKUP;
+import static java.lang.invoke.MethodHandleNatives.Constants.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* The JVM interface for the method handles package is all here.
@@ -81,14 +80,12 @@ class MethodHandleNatives {
* This routine is for debugging and reflection.
*/
static MemberName getMethodName(MethodHandle self) {
- if (!JVM_SUPPORT) return null;
return (MemberName) getTarget(self, ETF_METHOD_NAME);
}
/** Fetch the reflective version of the handled method, if available.
*/
static AccessibleObject getTargetMethod(MethodHandle self) {
- if (!JVM_SUPPORT) return null;
return (AccessibleObject) getTarget(self, ETF_REFLECT_METHOD);
}
@@ -97,7 +94,6 @@ class MethodHandleNatives {
* If it is chained to another method handle, return that handle.
*/
static Object getTargetInfo(MethodHandle self) {
- if (!JVM_SUPPORT) return null;
return getTarget(self, ETF_HANDLE_OR_METHOD_NAME);
}
@@ -111,11 +107,6 @@ class MethodHandleNatives {
*/
static native int getConstant(int which);
- /** True iff this HotSpot JVM has built-in support for method handles.
- * If false, some test cases might run, but functionality will be missing.
- */
- public static final boolean JVM_SUPPORT;
-
/** Java copy of MethodHandlePushLimit in range 2..255. */
static final int JVM_PUSH_LIMIT;
/** JVM stack motion (in words) after one slot is pushed, usually -1.
@@ -127,31 +118,24 @@ class MethodHandleNatives {
private static native void registerNatives();
static {
- boolean JVM_SUPPORT_;
int JVM_PUSH_LIMIT_;
int JVM_STACK_MOVE_UNIT_;
int CONV_OP_IMPLEMENTED_MASK_;
try {
registerNatives();
- JVM_SUPPORT_ = true;
JVM_PUSH_LIMIT_ = getConstant(Constants.GC_JVM_PUSH_LIMIT);
JVM_STACK_MOVE_UNIT_ = getConstant(Constants.GC_JVM_STACK_MOVE_UNIT);
CONV_OP_IMPLEMENTED_MASK_ = getConstant(Constants.GC_CONV_OP_IMPLEMENTED_MASK);
//sun.reflect.Reflection.registerMethodsToFilter(MethodHandleImpl.class, "init");
} catch (UnsatisfiedLinkError ee) {
// ignore; if we use init() methods later we'll see linkage errors
- JVM_SUPPORT_ = false;
JVM_PUSH_LIMIT_ = 3; // arbitrary
JVM_STACK_MOVE_UNIT_ = -1; // arbitrary
CONV_OP_IMPLEMENTED_MASK_ = 0;
- //System.out.println("Warning: Running with JVM_SUPPORT=false");
- //System.out.println(ee);
- JVM_SUPPORT = JVM_SUPPORT_;
JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
throw ee; // just die; hopeless to try to run with an older JVM
}
- JVM_SUPPORT = JVM_SUPPORT_;
JVM_PUSH_LIMIT = JVM_PUSH_LIMIT_;
JVM_STACK_MOVE_UNIT = JVM_STACK_MOVE_UNIT_;
if (CONV_OP_IMPLEMENTED_MASK_ == 0)
@@ -189,9 +173,15 @@ class MethodHandleNatives {
MN_SEARCH_INTERFACES = 0x00200000, // for MHN.getMembers
VM_INDEX_UNINITIALIZED = -99;
+ // BoundMethodHandle
+ /** Constants for decoding the vmargslot field, which contains 2 values. */
+ static final int
+ ARG_SLOT_PUSH_SHIFT = 16,
+ ARG_SLOT_MASK = (1< rtype, Class>[] ptypes) {
- MethodType.genericMethodType(0); // trigger initialization
- return MethodTypeImpl.makeImpl(Access.TOKEN, rtype, ptypes, true);
+ return MethodType.makeImpl(rtype, ptypes, true);
}
/**
* The JVM wants to use a MethodType with invokeGeneric. Give the runtime fair warning.
*/
static void notifyGenericMethodType(MethodType type) {
- try {
- // Trigger adapter creation.
- InvokeGeneric.genericInvokerOf(type);
- } catch (Exception ex) {
- Error err = new InternalError("Exception while resolving invokeGeneric");
- err.initCause(ex);
- throw err;
+ type.form().notifyGenericMethodType();
+ }
+
+ /**
+ * The JVM wants to raise an exception. Here's the path.
+ */
+ static void raiseException(int code, Object actual, Object required) {
+ String message;
+ // disregard the identity of the actual object, if it is not a class:
+ if (!(actual instanceof Class) && !(actual instanceof MethodType))
+ actual = actual.getClass();
+ if (actual != null)
+ message = "required "+required+" but encountered "+actual;
+ else
+ message = "required "+required;
+ switch (code) {
+ case 192: // checkcast
+ throw new ClassCastException(message);
+ default:
+ throw new InternalError("unexpected code "+code+": "+message);
}
}
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java
new file mode 100644
index 00000000000..6ea8f978b63
--- /dev/null
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2011, 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 java.lang.invoke;
+
+/**
+ * This class consists exclusively of static names internal to the
+ * method handle implementation.
+ * Usage: {@code import static java.lang.invoke.MethodHandleStatics.*}
+ * @author John Rose, JSR 292 EG
+ */
+/*non-public*/ class MethodHandleStatics {
+
+ private MethodHandleStatics() { } // do not instantiate
+
+ /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
+ if (type == null)
+ type = target.type();
+ MemberName name = null;
+ if (target != null)
+ name = MethodHandleNatives.getMethodName(target);
+ if (name == null)
+ return "invoke" + type;
+ return name.getName() + type;
+ }
+
+ /*non-public*/ static String getNameString(MethodHandle target, MethodHandle typeHolder) {
+ return getNameString(target, typeHolder == null ? (MethodType) null : typeHolder.type());
+ }
+
+ /*non-public*/ static String getNameString(MethodHandle target) {
+ return getNameString(target, (MethodType) null);
+ }
+
+ /*non-public*/ static String addTypeString(Object obj, MethodHandle target) {
+ String str = String.valueOf(obj);
+ if (target == null) return str;
+ int paren = str.indexOf('(');
+ if (paren >= 0) str = str.substring(0, paren);
+ return str + target.type();
+ }
+
+ static void checkSpreadArgument(Object av, int n) {
+ if (av == null ? n != 0 : ((Object[])av).length != n)
+ throw newIllegalArgumentException("Array is not of length "+n);
+ }
+
+ // handy shared exception makers (they simplify the common case code)
+ /*non-public*/ static RuntimeException newIllegalStateException(String message) {
+ return new IllegalStateException(message);
+ }
+ /*non-public*/ static RuntimeException newIllegalStateException(String message, Object obj) {
+ return new IllegalStateException(message(message, obj));
+ }
+ /*non-public*/ static RuntimeException newIllegalArgumentException(String message) {
+ return new IllegalArgumentException(message);
+ }
+ /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj) {
+ return new IllegalArgumentException(message(message, obj));
+ }
+ /*non-public*/ static Error uncaughtException(Exception ex) {
+ Error err = new InternalError("uncaught exception");
+ err.initCause(ex);
+ return err;
+ }
+ private static String message(String message, Object obj) {
+ if (obj != null) message = message + ": " + obj;
+ return message;
+ }
+}
diff --git a/jdk/src/share/classes/java/dyn/MethodHandles.java b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
similarity index 90%
rename from jdk/src/share/classes/java/dyn/MethodHandles.java
rename to jdk/src/share/classes/java/lang/invoke/MethodHandles.java
index 3bc9bd4a327..12e36da623a 100644
--- a/jdk/src/share/classes/java/dyn/MethodHandles.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
@@ -23,24 +23,18 @@
* questions.
*/
-package java.dyn;
+package java.lang.invoke;
import java.lang.reflect.*;
-import sun.dyn.Access;
-import sun.dyn.MemberName;
-import sun.dyn.MethodHandleImpl;
-import sun.dyn.WrapperInstance;
-import sun.dyn.util.ValueConversions;
-import sun.dyn.util.VerifyAccess;
-import sun.dyn.util.Wrapper;
+import sun.invoke.WrapperInstance;
+import sun.invoke.util.ValueConversions;
+import sun.invoke.util.VerifyAccess;
+import sun.invoke.util.Wrapper;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
-import sun.dyn.Invokers;
-import sun.dyn.MethodTypeImpl;
import sun.reflect.Reflection;
-import static sun.dyn.MemberName.newIllegalArgumentException;
-import static sun.dyn.MemberName.newNoAccessException;
+import static java.lang.invoke.MethodHandleStatics.*;
/**
* This class consists exclusively of static methods that operate on or return
@@ -49,7 +43,7 @@ import static sun.dyn.MemberName.newNoAccessException;
* Lookup methods which help create method handles for methods and fields.
* Combinator methods, which combine or transform pre-existing method handles into new ones.
* Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
- * Wrapper methods which can convert between method handles and other function-like "SAM types".
+ * Wrapper methods which can convert between method handles and interface types.
*
*
* @author John Rose, JSR 292 EG
@@ -58,15 +52,14 @@ public class MethodHandles {
private MethodHandles() { } // do not instantiate
- private static final Access IMPL_TOKEN = Access.getToken();
- private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
+ private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
static { MethodHandleImpl.initStatics(); }
// See IMPL_LOOKUP below.
//// Method handle creation from ordinary methods.
/**
- * Return a {@link Lookup lookup object} on the caller,
+ * Returns a {@link Lookup lookup object} on the caller,
* which has the capability to access any method handle that the caller has access to,
* including direct method handles to private fields and methods.
* This lookup object is a capability which may be delegated to trusted agents.
@@ -77,7 +70,7 @@ public class MethodHandles {
}
/**
- * Return a {@link Lookup lookup object} which is trusted minimally.
+ * Returns a {@link Lookup lookup object} which is trusted minimally.
* It can only be used to create method handles to
* publicly accessible fields and methods.
*
@@ -120,55 +113,55 @@ public class MethodHandles {
*
* lookup expression member behavior
*
- * {@linkplain java.dyn.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}
* FT f; (T) this.f;
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)}
* static FT f; (T) C.f;
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)}
* FT f; this.f = x;
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)}
* static FT f; C.f = arg;
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)}
* T m(A*); (T) this.m(arg*);
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)}
* static T m(A*); (T) C.m(arg*);
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)}
* T m(A*); (T) super.m(arg*);
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)}
* C(A*); (T) new C(arg*);
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)}
* (static)? FT f; (FT) aField.get(thisOrNull);
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)}
* (static)? FT f; aField.set(thisOrNull, arg);
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}
* (static)? T m(A*); (T) aMethod.invoke(thisOrNull, arg*);
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)}
* C(A*); (C) aConstructor.newInstance(arg*);
*
*
- * {@linkplain java.dyn.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}
* (static)? T m(A*); (T) aMethod.invoke(thisOrNull, arg*);
*
*
@@ -383,10 +376,10 @@ public class MethodHandles {
* and {@linkplain #PACKAGE PACKAGE (0x08)}.
*
* A freshly-created lookup object
- * on the {@linkplain java.dyn.MethodHandles#lookup() caller's class}
+ * on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
* has all possible bits set, since the caller class can access all its own members.
* A lookup object on a new lookup class
- * {@linkplain java.dyn.MethodHandles.Lookup#in created from a previous lookup object}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
* may have some mode bits set to zero.
* The purpose of this is to restrict access via the new lookup object,
* so that it can access only names which can be reached by the original
@@ -410,9 +403,8 @@ public class MethodHandles {
checkUnprivilegedlookupClass(lookupClass);
}
- Lookup(Access token, Class> lookupClass) {
+ Lookup(Class> lookupClass) {
this(lookupClass, ALL_MODES);
- Access.check(token);
}
private Lookup(Class> lookupClass, int allowedModes) {
@@ -471,7 +463,7 @@ public class MethodHandles {
}
// Make sure outer class is initialized first.
- static { IMPL_TOKEN.getClass(); }
+ static { IMPL_NAMES.getClass(); }
/** Version of lookup which is trusted minimally.
* It can only be used to create method handles to
@@ -481,11 +473,10 @@ public class MethodHandles {
/** Package-private version of lookup which is trusted. */
static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
- static { MethodHandleImpl.initLookup(IMPL_TOKEN, IMPL_LOOKUP); }
private static void checkUnprivilegedlookupClass(Class> lookupClass) {
String name = lookupClass.getName();
- if (name.startsWith("java.dyn.") || name.startsWith("sun.dyn."))
+ if (name.startsWith("java.lang.invoke."))
throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
}
@@ -506,8 +497,8 @@ public class MethodHandles {
* access (public, package, private, and protected) is allowed.
* In this case, no suffix is added.
* This is true only of an object obtained originally from
- * {@link java.dyn.MethodHandles#lookup MethodHandles.lookup}.
- * Objects created by {@link java.dyn.MethodHandles.Lookup#in Lookup.in}
+ * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
+ * Objects created by {@link java.lang.invoke.MethodHandles.Lookup#in Lookup.in}
* always have restricted access, and will display a suffix.
*
* (It may seem strange that protected access should be
@@ -577,7 +568,7 @@ public class MethodHandles {
MethodHandle findStatic(Class> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
MemberName method = resolveOrFail(refc, name, type, true);
checkMethod(refc, method, true);
- return MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull());
+ return MethodHandleImpl.findMethod(method, false, lookupClassOrNull());
}
/**
@@ -601,8 +592,8 @@ public class MethodHandles {
* if the class is {@code MethodHandle} and the name string is
* {@code invokeExact} or {@code invokeGeneric}, the resulting
* method handle is equivalent to one produced by
- * {@link java.dyn.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
- * {@link java.dyn.MethodHandles#genericInvoker MethodHandles.genericInvoker}
+ * {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
+ * {@link java.lang.invoke.MethodHandles#genericInvoker MethodHandles.genericInvoker}
* with the same {@code type} argument.
*
* @param refc the class or interface from which the method is accessed
@@ -618,7 +609,7 @@ public class MethodHandles {
public MethodHandle findVirtual(Class> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
MemberName method = resolveOrFail(refc, name, type, false);
checkMethod(refc, method, false);
- MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
+ MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
return restrictProtectedReceiver(method, mh);
}
@@ -651,8 +642,8 @@ public class MethodHandles {
MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull());
assert(ctor.isConstructor());
checkAccess(refc, ctor);
- MethodHandle rawMH = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull());
- MethodHandle allocMH = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawMH);
+ MethodHandle rawMH = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull());
+ MethodHandle allocMH = MethodHandleImpl.makeAllocator(rawMH);
return fixVarargs(allocMH, rawMH);
}
@@ -708,7 +699,7 @@ public class MethodHandles {
checkSpecialCaller(specialCaller);
MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller);
checkMethod(refc, method, false);
- MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, specialCaller);
+ MethodHandle mh = MethodHandleImpl.findMethod(method, false, specialCaller);
return restrictReceiver(method, mh, specialCaller);
}
@@ -839,17 +830,17 @@ return mh1;
Class extends Object> refc = receiver.getClass(); // may get NPE
MemberName method = resolveOrFail(refc, name, type, false);
checkMethod(refc, method, false);
- MethodHandle dmh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
- MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, dmh, receiver);
+ MethodHandle dmh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
+ MethodHandle bmh = MethodHandleImpl.bindReceiver(dmh, receiver);
if (bmh == null)
- throw newNoAccessException(method, this);
+ throw method.makeAccessException("no access", this);
if (dmh.type().parameterCount() == 0)
return dmh; // bound the trailing parameter; no varargs possible
return fixVarargs(bmh, dmh);
}
/**
- * Make a direct method handle to m , if the lookup class has permission.
+ * Makes a direct method handle to m , if the lookup class has permission.
* If m is non-static, the receiver argument is treated as an initial argument.
* If m is virtual, overriding is respected on every call.
* Unlike the Core Reflection API, exceptions are not wrapped.
@@ -871,7 +862,7 @@ return mh1;
MemberName method = new MemberName(m);
assert(method.isMethod());
if (!m.isAccessible()) checkMethod(method.getDeclaringClass(), method, method.isStatic());
- MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, true, lookupClassOrNull());
+ MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
if (!m.isAccessible()) mh = restrictProtectedReceiver(method, mh);
return mh;
}
@@ -901,7 +892,7 @@ return mh1;
assert(method.isMethod());
// ignore m.isAccessible: this is a new kind of access
checkMethod(m.getDeclaringClass(), method, false);
- MethodHandle mh = MethodHandleImpl.findMethod(IMPL_TOKEN, method, false, lookupClassOrNull());
+ MethodHandle mh = MethodHandleImpl.findMethod(method, false, lookupClassOrNull());
return restrictReceiver(method, mh, specialCaller);
}
@@ -928,8 +919,8 @@ return mh1;
MemberName ctor = new MemberName(c);
assert(ctor.isConstructor());
if (!c.isAccessible()) checkAccess(c.getDeclaringClass(), ctor);
- MethodHandle rawCtor = MethodHandleImpl.findMethod(IMPL_TOKEN, ctor, false, lookupClassOrNull());
- MethodHandle allocator = MethodHandleImpl.makeAllocator(IMPL_TOKEN, rawCtor);
+ MethodHandle rawCtor = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull());
+ MethodHandle allocator = MethodHandleImpl.makeAllocator(rawCtor);
return fixVarargs(allocator, rawCtor);
}
@@ -940,7 +931,7 @@ return mh1;
* If the field is static, the method handle will take no arguments.
* Otherwise, its single argument will be the instance containing
* the field.
- * If the method's {@code accessible} flag is not set,
+ * If the field's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* @param f the reflected field
* @return a method handle which can load values from the reflected field
@@ -958,7 +949,7 @@ return mh1;
* argument, of the field's value type, the value to be stored.
* Otherwise, the two arguments will be the instance containing
* the field, and the value to be stored.
- * If the method's {@code accessible} flag is not set,
+ * If the field's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
* @param f the reflected field
* @return a method handle which can store values into the reflected field
@@ -999,7 +990,7 @@ return mh1;
void checkSymbolicClass(Class> refc) throws IllegalAccessException {
Class> caller = lookupClassOrNull();
if (caller != null && !VerifyAccess.isClassAccessible(refc, caller))
- throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), this);
+ throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this);
}
void checkMethod(Class> refc, MemberName m, boolean wantStatic) throws IllegalAccessException {
@@ -1012,7 +1003,7 @@ return mh1;
message = wantStatic ? "expected a static method" : "expected a non-static method";
else
{ checkAccess(refc, m); return; }
- throw newNoAccessException(message, m, this);
+ throw m.makeAccessException(message, this);
}
void checkAccess(Class> refc, MemberName m) throws IllegalAccessException {
@@ -1030,7 +1021,7 @@ return mh1;
&& VerifyAccess.isSamePackage(m.getDeclaringClass(), lookupClass()))
// Protected members can also be checked as if they were package-private.
return;
- throw newNoAccessException(accessFailedMessage(refc, m), m, this);
+ throw m.makeAccessException(accessFailedMessage(refc, m), this);
}
String accessFailedMessage(Class> refc, MemberName m) {
@@ -1064,8 +1055,8 @@ return mh1;
|| (specialCaller != lookupClass()
&& !(ALLOW_NESTMATE_ACCESS &&
VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
- throw newNoAccessException("no private access for invokespecial",
- new MemberName(specialCaller), this);
+ throw new MemberName(specialCaller).
+ makeAccessException("no private access for invokespecial", this);
}
MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws IllegalAccessException {
@@ -1084,12 +1075,12 @@ return mh1;
assert(!method.isStatic());
Class> defc = method.getDeclaringClass(); // receiver type of mh is too wide
if (defc.isInterface() || !defc.isAssignableFrom(caller)) {
- throw newNoAccessException("caller class must be a subclass below the method", method, caller);
+ throw method.makeAccessException("caller class must be a subclass below the method", caller);
}
MethodType rawType = mh.type();
if (rawType.parameterType(0) == caller) return mh;
MethodType narrowType = rawType.changeParameterType(0, caller);
- MethodHandle narrowMH = MethodHandleImpl.convertArguments(IMPL_TOKEN, mh, narrowType, rawType, null);
+ MethodHandle narrowMH = MethodHandleImpl.convertArguments(mh, narrowType, rawType, null);
return fixVarargs(narrowMH, mh);
}
@@ -1097,10 +1088,9 @@ return mh1;
boolean isStatic, boolean isSetter) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(refc, name, type, isStatic);
if (isStatic != field.isStatic())
- throw newNoAccessException(isStatic
- ? "expected a static field"
- : "expected a non-static field",
- field, this);
+ throw field.makeAccessException(isStatic
+ ? "expected a static field"
+ : "expected a non-static field", this);
return makeAccessor(refc, field, false, isSetter);
}
@@ -1108,9 +1098,9 @@ return mh1;
boolean trusted, boolean isSetter) throws IllegalAccessException {
assert(field.isField());
if (trusted)
- return MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull());
+ return MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull());
checkAccess(refc, field);
- MethodHandle mh = MethodHandleImpl.accessField(IMPL_TOKEN, field, isSetter, lookupClassOrNull());
+ MethodHandle mh = MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull());
return restrictProtectedReceiver(field, mh);
}
}
@@ -1127,7 +1117,7 @@ return mh1;
*/
public static
MethodHandle arrayElementGetter(Class> arrayClass) throws IllegalArgumentException {
- return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, false);
+ return MethodHandleImpl.accessArrayElement(arrayClass, false);
}
/**
@@ -1141,7 +1131,7 @@ return mh1;
*/
public static
MethodHandle arrayElementSetter(Class> arrayClass) throws IllegalArgumentException {
- return MethodHandleImpl.accessArrayElement(IMPL_TOKEN, arrayClass, true);
+ return MethodHandleImpl.accessArrayElement(arrayClass, true);
}
/// method handle invocation (reflective style)
@@ -1191,7 +1181,7 @@ return invoker;
MethodHandle spreadInvoker(MethodType type, int objectArgCount) {
if (objectArgCount < 0 || objectArgCount > type.parameterCount())
throw new IllegalArgumentException("bad argument count "+objectArgCount);
- return invokers(type).spreadInvoker(objectArgCount);
+ return type.invokers().spreadInvoker(objectArgCount);
}
/**
@@ -1231,7 +1221,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)
*/
static public
MethodHandle exactInvoker(MethodType type) {
- return invokers(type).exactInvoker();
+ return type.invokers().exactInvoker();
}
/**
@@ -1258,11 +1248,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
*/
static public
MethodHandle genericInvoker(MethodType type) {
- return invokers(type).genericInvoker();
- }
-
- static Invokers invokers(MethodType type) {
- return MethodTypeImpl.invokers(IMPL_TOKEN, type);
+ return type.invokers().genericInvoker();
}
/**
@@ -1387,7 +1373,7 @@ publicLookup().findVirtual(MethodHandle.class, "invokeGeneric", type)
return target;
MethodHandle res = null;
try {
- res = MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
+ res = MethodHandleImpl.convertArguments(target,
newType, oldType, null);
} catch (IllegalArgumentException ex) {
}
@@ -1531,7 +1517,7 @@ assert((int)twice.invokeExact(21) == 42);
MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
MethodType oldType = target.type();
checkReorder(reorder, newType, oldType);
- return MethodHandleImpl.convertArguments(IMPL_TOKEN, target,
+ return MethodHandleImpl.convertArguments(target,
newType, oldType,
reorder);
}
@@ -1574,7 +1560,7 @@ assert((int)twice.invokeExact(21) == 42);
int numSpread = (outargs - spreadPos);
MethodHandle res = null;
if (spreadPos >= 0 && numSpread >= 0) {
- res = MethodHandleImpl.spreadArguments(IMPL_TOKEN, target, newType, spreadPos);
+ res = MethodHandleImpl.spreadArguments(target, newType, spreadPos);
}
if (res == null) {
throw newIllegalArgumentException("cannot spread "+newType+" to " +oldType);
@@ -1607,7 +1593,7 @@ assert((int)twice.invokeExact(21) == 42);
int numCollect = (inargs - collectPos);
if (collectPos < 0 || numCollect < 0)
throw newIllegalArgumentException("wrong number of arguments");
- MethodHandle res = MethodHandleImpl.collectArguments(IMPL_TOKEN, target, newType, collectPos, null);
+ MethodHandle res = MethodHandleImpl.collectArguments(target, newType, collectPos, null);
if (res == null) {
throw newIllegalArgumentException("cannot collect from "+newType+" to " +oldType);
}
@@ -1654,7 +1640,13 @@ assert((int)twice.invokeExact(21) == 42);
MethodHandle identity(Class> type) {
if (type == void.class)
throw newIllegalArgumentException("void type");
- return ValueConversions.identity(type);
+ else if (type == Object.class)
+ return ValueConversions.identity();
+ else if (type.isPrimitive())
+ return ValueConversions.identity(Wrapper.forPrimitiveType(type));
+ else
+ return AdapterMethodHandle.makeRetypeRaw(
+ MethodType.methodType(type, type), ValueConversions.identity());
}
/**
@@ -1686,8 +1678,6 @@ assert((int)twice.invokeExact(21) == 42);
MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
int insCount = values.length;
MethodType oldType = target.type();
- ArrayList> ptypes =
- new ArrayList>(oldType.parameterList());
int outargs = oldType.parameterCount();
int inargs = outargs - insCount;
if (inargs < 0)
@@ -1701,14 +1691,14 @@ assert((int)twice.invokeExact(21) == 42);
value = checkValue(valueType, value);
if (pos == 0 && !valueType.isPrimitive()) {
// At least for now, make bound method handles a special case.
- MethodHandle bmh = MethodHandleImpl.bindReceiver(IMPL_TOKEN, result, value);
+ MethodHandle bmh = MethodHandleImpl.bindReceiver(result, value);
if (bmh != null) {
result = bmh;
continue;
}
// else fall through to general adapter machinery
}
- result = MethodHandleImpl.bindArgument(IMPL_TOKEN, result, pos, value);
+ result = MethodHandleImpl.bindArgument(result, pos, value);
}
return result;
}
@@ -1726,20 +1716,21 @@ assert((int)twice.invokeExact(21) == 42);
*
* Example:
*
-import static java.dyn.MethodHandles.*;
-import static java.dyn.MethodType.*;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
-MethodHandle d0 = dropArguments(cat, 0, String.class);
-assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
-MethodHandle d1 = dropArguments(cat, 1, String.class);
-assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
-MethodHandle d2 = dropArguments(cat, 2, String.class);
-assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
-MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
-assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
+MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
+MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
+assertEquals(bigType, d0.type());
+assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
+ *
+ *
+ * This method is also equivalent to the following code:
+ *
+ * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}(target, pos, valueTypes.toArray(new Class[0]))
*
* @param target the method handle to invoke after the arguments are dropped
* @param valueTypes the type(s) of the argument(s) to drop
@@ -1762,7 +1753,7 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
new ArrayList>(oldType.parameterList());
ptypes.addAll(pos, valueTypes);
MethodType newType = MethodType.methodType(oldType.returnType(), ptypes);
- return MethodHandleImpl.dropArguments(IMPL_TOKEN, target, newType, pos);
+ return MethodHandleImpl.dropArguments(target, newType, pos);
}
/**
@@ -1770,10 +1761,34 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
* after dropping the given argument(s) at the given position.
* The type of the new method handle will insert the given argument
* type(s), at that position, into the original handle's type.
- * This method is equivalent to the following code:
- *
+ *
+ * The pos may range between zero and N ,
+ * where N is the number of argument types in target ,
+ * meaning to drop the first or last argument (respectively),
+ * or an argument somewhere in between.
+ *
+ * Example:
+ *
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle d0 = dropArguments(cat, 0, String.class);
+assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
+MethodHandle d1 = dropArguments(cat, 1, String.class);
+assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
+MethodHandle d2 = dropArguments(cat, 2, String.class);
+assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
+MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
+ *
+ *
+ * This method is also equivalent to the following code:
+ *
* {@link #dropArguments(MethodHandle,int,List) dropArguments}(target, pos, Arrays.asList(valueTypes))
- *
+ *
* @param target the method handle to invoke after the arguments are dropped
* @param valueTypes the type(s) of the argument(s) to drop
* @param pos position of first argument to drop (zero for the leftmost)
@@ -1789,7 +1804,7 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
}
/**
- * Adapt a target method handle {@code target} by pre-processing
+ * Adapts a target method handle {@code target} by pre-processing
* one or more of its arguments, each with its own unary filter function,
* and then calling the target with each pre-processed argument
* replaced by the result of its corresponding filter function.
@@ -1812,8 +1827,8 @@ assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
* which do not correspond to argument positions in the target.
* Example:
*
-import static java.dyn.MethodHandles.*;
-import static java.dyn.MethodType.*;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
@@ -1855,16 +1870,16 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
|| filterType.returnType() != targetType.parameterType(curPos))
throw newIllegalArgumentException("target and filter types do not match");
adapterType = adapterType.changeParameterType(curPos, filterType.parameterType(0));
- adapter = MethodHandleImpl.filterArgument(IMPL_TOKEN, adapter, curPos, filter);
+ adapter = MethodHandleImpl.filterArgument(adapter, curPos, filter);
}
MethodType midType = adapter.type();
if (midType != adapterType)
- adapter = MethodHandleImpl.convertArguments(IMPL_TOKEN, adapter, adapterType, midType, null);
+ adapter = MethodHandleImpl.convertArguments(adapter, adapterType, midType, null);
return adapter;
}
/**
- * Adapt a target method handle {@code target} by post-processing
+ * Adapts a target method handle {@code target} by post-processing
* its return value with a unary filter function.
*
* If a filter {@code F} applies to the return value of
@@ -1876,8 +1891,8 @@ assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
* return type of the target.
* Example:
*
-import static java.dyn.MethodHandles.*;
-import static java.dyn.MethodType.*;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
...
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
@@ -1909,7 +1924,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
/**
- * Adapt a target method handle {@code target} by pre-processing
+ * Adapts a target method handle {@code target} by pre-processing
* some of its arguments, and then calling the target with
* the result of the pre-processing, plus all original arguments.
*
@@ -1966,11 +1981,11 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
if (!ok)
throw misMatchedTypes("target and combiner types", targetType, combinerType);
MethodType newType = targetType.dropParameterTypes(0, 1);
- return MethodHandleImpl.foldArguments(IMPL_TOKEN, target, newType, combiner);
+ return MethodHandleImpl.foldArguments(target, newType, combiner);
}
/**
- * Make a method handle which adapts a target method handle,
+ * Makes a method handle which adapts a target method handle,
* by guarding it with a test, a boolean-valued method handle.
* If the guard fails, a fallback handle is called instead.
* All three method handles must have the same corresponding
@@ -2021,7 +2036,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
test = dropArguments(test, gpc, targs.subList(gpc, tpc));
gtype = test.type();
}
- return MethodHandleImpl.makeGuardWithTest(IMPL_TOKEN, test, target, fallback);
+ return MethodHandleImpl.makeGuardWithTest(test, target, fallback);
}
static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) {
@@ -2029,7 +2044,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
/**
- * Make a method handle which adapts a target method handle,
+ * Makes a method handle which adapts a target method handle,
* by running it inside an exception handler.
* If the target returns normally, the adapter returns that value.
* If an exception matching the specified type is thrown, the fallback
@@ -2092,7 +2107,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
handler = dropArguments(handler, hpc, hargs.subList(hpc, tpc));
htype = handler.type();
}
- return MethodHandleImpl.makeGuardWithCatch(IMPL_TOKEN, target, exType, handler);
+ return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
}
/**
@@ -2107,51 +2122,45 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
*/
public static
MethodHandle throwException(Class> returnType, Class extends Throwable> exType) {
- return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.methodType(returnType, exType));
+ return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType));
}
/**
- * Produces an instance of the given "SAM" interface which redirects
+ * Produces an instance of the given single-method interface which redirects
* its calls to the given method handle.
*
- * A SAM interface is an interface which declares a single abstract method.
- * When determining the unique abstract method of a SAM interface,
+ * A single-method interface is an interface which declares a unique method.
+ * When determining the unique method of a single-method interface,
* the public {@code Object} methods ({@code toString}, {@code equals}, {@code hashCode})
- * are disregarded. For example, {@link java.util.Comparator} is a SAM interface,
+ * are disregarded. For example, {@link java.util.Comparator} is a single-method interface,
* even though it re-declares the {@code Object.equals} method.
- * Also, if the SAM interface has a supertype,
- * the SAM interface may override an inherited method.
- * Any such overrides are respected, and the method handle will be accessible
- * by either the inherited method or the SAM method.
- * In particular, a {@linkplain java.lang.reflect.Method#isBridge bridge method}
- * may be created if the methods have different return types.
*
* The type must be public. No additional access checks are performed.
*
- * The resulting instance of the required SAM type will respond to
- * invocation of the SAM type's single abstract method by calling
+ * The resulting instance of the required type will respond to
+ * invocation of the type's single abstract method by calling
* the given {@code target} on the incoming arguments,
* and returning or throwing whatever the {@code target}
* returns or throws. The invocation will be as if by
* {@code target.invokeGeneric}.
- * The target's type will be checked before the SAM
+ * The target's type will be checked before the
* instance is created, as if by a call to {@code asType},
* which may result in a {@code WrongMethodTypeException}.
*
- * The wrapper instance will implement the requested SAM interface
- * and its super-types, but no other SAM types.
- * This means that the SAM instance will not unexpectedly
+ * The wrapper instance will implement the requested interface
+ * and its super-types, but no other single-method interfaces.
+ * This means that the instance will not unexpectedly
* pass an {@code instanceof} test for any unrequested type.
*
* Implementation Note:
- * Therefore, each SAM instance must implement a unique SAM type.
+ * Therefore, each instance must implement a unique single-method interface.
* Implementations may not bundle together
- * multiple SAM types onto single implementation classes
+ * multiple single-method interfaces onto single implementation classes
* in the style of {@link java.awt.AWTEventMulticaster}.
*
* The method handle may throw an undeclared exception ,
* which means any checked exception (or other checked throwable)
- * not declared by the SAM type's single abstract method.
+ * not declared by the requested type's single abstract method.
* If this happens, the throwable will be wrapped in an instance of
* {@link java.lang.reflect.UndeclaredThrowableException UndeclaredThrowableException}
* and thrown in that wrapped form.
@@ -2161,28 +2170,37 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
* by their behavior.
* It is not guaranteed to return a new instance for every call.
*
+ * Because of the possibility of {@linkplain java.lang.reflect.Method#isBridge bridge methods}
+ * and other corner cases, the interface may also have several abstract methods
+ * with the same name but having distinct descriptors (types of returns and parameters).
+ * In this case, all the methods are bound in common to the one given {@code target}.
+ * The type check and effective {@code asType} conversion is applied to each
+ * method type descriptor, and all abstract methods are bound to the {@code target} in common.
+ * Beyond this type check, no further checks are made to determine that the
+ * abstract methods are related in any way.
+ *
* Future versions of this API may accept additional types,
* such as abstract classes with single abstract methods.
* Future versions of this API may also equip wrapper instances
* with one or more additional public "marker" interfaces.
*
* @param target the method handle to invoke from the wrapper
- * @param samType the desired type of the wrapper, a SAM type
+ * @param smType the desired type of the wrapper, a single-method interface
* @return a correctly-typed wrapper for the given {@code target}
* @throws NullPointerException if either argument is null
- * @throws IllegalArgumentException if the {@code samType} is not a
+ * @throws IllegalArgumentException if the {@code smType} is not a
* valid argument to this method
* @throws WrongMethodTypeException if the {@code target} cannot
- * be converted to the type required by the SAM type
+ * be converted to the type required by the requested interface
*/
// Other notes to implementors:
//
- // No stable mapping is promised between the SAM type and
+ // No stable mapping is promised between the single-method interface and
// the implementation class C. Over time, several implementation
- // classes might be used for the same SAM type.
+ // classes might be used for the same type.
//
// If the implementation is able
- // to prove that a wrapper of the required SAM type
+ // to prove that a wrapper of the required type
// has already been created for a given
// method handle, or for another method handle with the
// same behavior, the implementation may return that wrapper in place of
@@ -2191,34 +2209,34 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
// This method is designed to apply to common use cases
// where a single method handle must interoperate with
// an interface that implements a function-like
- // API. Additional variations, such as SAM classes with
+ // API. Additional variations, such as single-abstract-method classes with
// private constructors, or interfaces with multiple but related
// entry points, must be covered by hand-written or automatically
// generated adapter classes.
//
public static
- T asInstance(final MethodHandle target, final Class samType) {
+ T asInstance(final MethodHandle target, final Class smType) {
// POC implementation only; violates the above contract several ways
- final Method sam = getSamMethod(samType);
- if (sam == null)
- throw new IllegalArgumentException("not a SAM type: "+samType.getName());
- MethodType samMT = MethodType.methodType(sam.getReturnType(), sam.getParameterTypes());
- MethodHandle checkTarget = target.asType(samMT); // make throw WMT
+ final Method sm = getSingleMethod(smType);
+ if (sm == null)
+ throw new IllegalArgumentException("not a single-method interface: "+smType.getName());
+ MethodType smMT = MethodType.methodType(sm.getReturnType(), sm.getParameterTypes());
+ MethodHandle checkTarget = target.asType(smMT); // make throw WMT
checkTarget = checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
- final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class, samMT.parameterCount());
- return samType.cast(Proxy.newProxyInstance(
- samType.getClassLoader(),
- new Class[]{ samType, WrapperInstance.class },
+ final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class, smMT.parameterCount());
+ return smType.cast(Proxy.newProxyInstance(
+ smType.getClassLoader(),
+ new Class[]{ smType, WrapperInstance.class },
new InvocationHandler() {
private Object getArg(String name) {
if ((Object)name == "getWrapperInstanceTarget") return target;
- if ((Object)name == "getWrapperInstanceType") return samType;
+ if ((Object)name == "getWrapperInstanceType") return smType;
throw new AssertionError();
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == WrapperInstance.class)
return getArg(method.getName());
- if (method.equals(sam))
+ if (method.equals(sm))
return vaTarget.invokeExact(args);
if (isObjectMethod(method))
return callObjectMethod(this, method, args);
@@ -2228,7 +2246,7 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
/**
- * Determine if the given object was produced by a call to {@link #asInstance asInstance}.
+ * Determines if the given object was produced by a call to {@link #asInstance asInstance}.
* @param x any reference
* @return true if the reference is not null and points to an object produced by {@code asInstance}
*/
@@ -2248,11 +2266,11 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
/**
* Produces or recovers a target method handle which is behaviorally
- * equivalent to the SAM method of this wrapper instance.
+ * equivalent to the unique method of this wrapper instance.
* The object {@code x} must have been produced by a call to {@link #asInstance asInstance}.
* This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
* @param x any reference
- * @return a method handle implementing the SAM method
+ * @return a method handle implementing the unique method
* @throws IllegalArgumentException if the reference x is not to a wrapper instance
*/
public static
@@ -2261,11 +2279,11 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
/**
- * Recover the SAM type for which this wrapper instance was created.
+ * Recovers the unique single-method interface type for which this wrapper instance was created.
* The object {@code x} must have been produced by a call to {@link #asInstance asInstance}.
* This requirement may be tested via {@link #isWrapperInstance isWrapperInstance}.
* @param x any reference
- * @return the SAM type for which the wrapper was created
+ * @return the single-method interface type for which the wrapper was created
* @throws IllegalArgumentException if the reference x is not to a wrapper instance
*/
public static
@@ -2305,24 +2323,24 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
}
private static
- Method getSamMethod(Class> samType) {
- Method sam = null;
- for (Method m : samType.getMethods()) {
+ Method getSingleMethod(Class> smType) {
+ Method sm = null;
+ for (Method m : smType.getMethods()) {
int mod = m.getModifiers();
if (Modifier.isAbstract(mod)) {
- if (sam != null && !isObjectMethod(sam))
+ if (sm != null && !isObjectMethod(sm))
return null; // too many abstract methods
- sam = m;
+ sm = m;
}
}
- if (!samType.isInterface() && getSamConstructor(samType) == null)
+ if (!smType.isInterface() && getSingleConstructor(smType) == null)
return null; // wrong kind of constructor
- return sam;
+ return sm;
}
private static
- Constructor getSamConstructor(Class> samType) {
- for (Constructor c : samType.getDeclaredConstructors()) {
+ Constructor getSingleConstructor(Class> smType) {
+ for (Constructor c : smType.getDeclaredConstructors()) {
if (c.getParameterTypes().length == 0) {
int mod = c.getModifiers();
if (Modifier.isPublic(mod) || Modifier.isProtected(mod))
@@ -2334,6 +2352,6 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
/*non-public*/
static MethodHandle asVarargsCollector(MethodHandle target, Class> arrayType) {
- return MethodHandleImpl.asVarargsCollector(IMPL_TOKEN, target, arrayType);
+ return MethodHandleImpl.asVarargsCollector(target, arrayType);
}
}
diff --git a/jdk/src/share/classes/java/dyn/MethodType.java b/jdk/src/share/classes/java/lang/invoke/MethodType.java
similarity index 93%
rename from jdk/src/share/classes/java/dyn/MethodType.java
rename to jdk/src/share/classes/java/lang/invoke/MethodType.java
index a7baf7c634e..a7fa147fa32 100644
--- a/jdk/src/share/classes/java/dyn/MethodType.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodType.java
@@ -23,18 +23,14 @@
* questions.
*/
-package java.dyn;
+package java.lang.invoke;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
-import sun.dyn.Access;
-import sun.dyn.Invokers;
-import sun.dyn.MethodHandleImpl;
-import sun.dyn.MethodTypeImpl;
-import sun.dyn.util.BytecodeDescriptor;
-import static sun.dyn.MemberName.newIllegalArgumentException;
+import sun.invoke.util.BytecodeDescriptor;
+import static java.lang.invoke.MethodHandleStatics.*;
/**
* A method type represents the arguments and return type accepted and
@@ -96,34 +92,6 @@ class MethodType implements java.io.Serializable {
private MethodType wrapAlt; // alternative wrapped/unwrapped version
private Invokers invokers; // cache of handy higher-order adapters
- private static final Access IMPL_TOKEN = Access.getToken();
-
- // share a cache with a friend in this package
- Invokers getInvokers() { return invokers; }
- void setInvokers(Invokers inv) { invokers = inv; }
-
- static {
- // This hack allows the implementation package special access to
- // the internals of MethodType. In particular, the MTImpl has all sorts
- // of cached information useful to the implementation code.
- MethodTypeImpl.setMethodTypeFriend(IMPL_TOKEN, new MethodTypeImpl.MethodTypeFriend() {
- public Class>[] ptypes(MethodType mt) { return mt.ptypes; }
- public MethodTypeImpl form(MethodType mt) { return mt.form; }
- public void setForm(MethodType mt, MethodTypeImpl form) {
- assert(mt.form == null);
- mt.form = (MethodTypeForm) form;
- }
- public MethodType makeImpl(Class> rtype, Class>[] ptypes, boolean trusted) {
- return MethodType.makeImpl(rtype, ptypes, trusted);
- }
- public MethodTypeImpl newMethodTypeForm(MethodType mt) {
- return new MethodTypeForm(mt);
- }
- public Invokers getInvokers(MethodType mt) { return mt.invokers; }
- public void setInvokers(MethodType mt, Invokers inv) { mt.invokers = inv; }
- });
- }
-
/**
* Check the given parameters for validity and store them into the final fields.
*/
@@ -134,6 +102,10 @@ class MethodType implements java.io.Serializable {
this.ptypes = ptypes;
}
+ /*trusted*/ MethodTypeForm form() { return form; }
+ /*trusted*/ Class> rtype() { return rtype; }
+ /*trusted*/ Class>[] ptypes() { return ptypes; }
+
private static void checkRtype(Class> rtype) {
rtype.equals(rtype); // null check
}
@@ -168,7 +140,7 @@ class MethodType implements java.io.Serializable {
static final Class>[] NO_PTYPES = {};
/**
- * Find or create an instance of the given method type.
+ * Finds or creates an instance of the given method type.
* @param rtype the return type
* @param ptypes the parameter types
* @return a method type with the given components
@@ -253,7 +225,7 @@ class MethodType implements java.io.Serializable {
* @param trusted whether the ptypes can be used without cloning
* @return the unique method type of the desired structure
*/
- private static
+ /*trusted*/ static
MethodType makeImpl(Class> rtype, Class>[] ptypes, boolean trusted) {
if (ptypes == null || ptypes.length == 0) {
ptypes = NO_PTYPES; trusted = true;
@@ -269,7 +241,12 @@ class MethodType implements java.io.Serializable {
// defensively copy the array passed in by the user
mt1 = new MethodType(rtype, ptypes.clone());
// promote the object to the Real Thing, and reprobe
- MethodTypeImpl.initForm(IMPL_TOKEN, mt1);
+ MethodTypeForm form = MethodTypeForm.findForm(mt1);
+ mt1.form = form;
+ if (form.erasedType == mt1) {
+ // This is a principal (erased) type; show it to the JVM.
+ MethodHandleNatives.init(mt1);
+ }
synchronized (internTable) {
mt0 = internTable.get(mt1);
if (mt0 != null)
@@ -279,12 +256,6 @@ class MethodType implements java.io.Serializable {
return mt1;
}
- // Entry point from JVM. TODO: Change the name & signature.
- private static MethodType makeImpl(Class> rtype, Class>[] ptypes,
- boolean ignore1, boolean ignore2) {
- return makeImpl(rtype, ptypes, true);
- }
-
private static final MethodType[] objectOnlyTypes = new MethodType[20];
/**
@@ -519,7 +490,7 @@ class MethodType implements java.io.Serializable {
}
/**
- * Convert all wrapper types to their corresponding primitive types.
+ * Converts all wrapper types to their corresponding primitive types.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* All primitive types (including {@code void}) will remain unchanged.
* A return type of {@code java.lang.Void} is changed to {@code void}.
@@ -535,7 +506,7 @@ class MethodType implements java.io.Serializable {
MethodType wt = pt.wrapAlt;
if (wt == null) {
// fill in lazily
- wt = MethodTypeImpl.canonicalize(pt, MethodTypeImpl.WRAP, MethodTypeImpl.WRAP);
+ wt = MethodTypeForm.canonicalize(pt, MethodTypeForm.WRAP, MethodTypeForm.WRAP);
assert(wt != null);
pt.wrapAlt = wt;
}
@@ -547,7 +518,7 @@ class MethodType implements java.io.Serializable {
MethodType uwt = wt.wrapAlt;
if (uwt == null) {
// fill in lazily
- uwt = MethodTypeImpl.canonicalize(wt, MethodTypeImpl.UNWRAP, MethodTypeImpl.UNWRAP);
+ uwt = MethodTypeForm.canonicalize(wt, MethodTypeForm.UNWRAP, MethodTypeForm.UNWRAP);
if (uwt == null)
uwt = wt; // type has no wrappers or prims at all
wt.wrapAlt = uwt;
@@ -658,7 +629,7 @@ class MethodType implements java.io.Serializable {
/// Queries which have to do with the bytecode architecture
/** Reports the number of JVM stack slots required to invoke a method
- * of this type. Note that (for historic reasons) the JVM requires
+ * of this type. Note that (for historical reasons) the JVM requires
* a second stack slot to pass long and double arguments.
* So this method returns {@link #parameterCount() parameterCount} plus the
* number of long and double parameters (if any).
@@ -666,12 +637,18 @@ class MethodType implements java.io.Serializable {
* This method is included for the benfit of applications that must
* generate bytecodes that process method handles and invokedynamic.
* @return the number of JVM stack slots for this type's parameters
- * @deprecated Will be removed for PFD.
*/
- public int parameterSlotCount() {
+ /*non-public*/ int parameterSlotCount() {
return form.parameterSlotCount();
}
+ /*non-public*/ Invokers invokers() {
+ Invokers inv = invokers;
+ if (inv != null) return inv;
+ invokers = inv = new Invokers(this);
+ return inv;
+ }
+
/** Reports the number of JVM stack slots which carry all parameters including and after
* the given position, which must be in the range of 0 to
* {@code parameterCount} inclusive. Successive parameters are
@@ -694,9 +671,8 @@ class MethodType implements java.io.Serializable {
* @return the index of the (shallowest) JVM stack slot transmitting the
* given parameter
* @throws IllegalArgumentException if {@code num} is negative or greater than {@code parameterCount()}
- * @deprecated Will be removed for PFD.
*/
- public int parameterSlotDepth(int num) {
+ /*non-public*/ int parameterSlotDepth(int num) {
if (num < 0 || num > ptypes.length)
parameterType(num); // force a range check
return form.parameterToArgSlot(num-1);
@@ -710,14 +686,14 @@ class MethodType implements java.io.Serializable {
* This method is included for the benfit of applications that must
* generate bytecodes that process method handles and invokedynamic.
* @return the number of JVM stack slots (0, 1, or 2) for this type's return value
- * @deprecated Will be removed for PFD.
+ * Will be removed for PFD.
*/
- public int returnSlotCount() {
+ /*non-public*/ int returnSlotCount() {
return form.returnSlotCount();
}
/**
- * Find or create an instance of a method type, given the spelling of its bytecode descriptor.
+ * Finds or creates an instance of a method type, given the spelling of its bytecode descriptor.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
* Any class or interface name embedded in the descriptor string
* will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
diff --git a/jdk/src/share/classes/sun/dyn/MethodTypeImpl.java b/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java
similarity index 85%
rename from jdk/src/share/classes/sun/dyn/MethodTypeImpl.java
rename to jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java
index 700ed307f74..db73b24d067 100644
--- a/jdk/src/share/classes/sun/dyn/MethodTypeImpl.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodTypeForm.java
@@ -23,11 +23,10 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
-import sun.dyn.util.Wrapper;
-import static sun.dyn.MemberName.newIllegalArgumentException;
+import sun.invoke.util.Wrapper;
+import static java.lang.invoke.MethodHandleStatics.*;
/**
* Shared information for a group of method types, which differ
@@ -42,7 +41,7 @@ import static sun.dyn.MemberName.newIllegalArgumentException;
* No more than half of these are likely to be loaded at once.
* @author John Rose
*/
-public class MethodTypeImpl {
+class MethodTypeForm {
final int[] argToSlotTable, slotToArgTable;
final long argCounts; // packed slot & value counts
final long primCounts; // packed prim & double counts
@@ -66,39 +65,10 @@ public class MethodTypeImpl {
return erasedType;
}
- public static MethodTypeImpl of(MethodType type) {
- return METHOD_TYPE_FRIEND.form(type);
- }
-
- /** Access methods for the internals of MethodType, supplied to
- * MethodTypeImpl as a trusted agent.
- */
- static public interface MethodTypeFriend {
- Class>[] ptypes(MethodType mt);
- MethodTypeImpl form(MethodType mt);
- void setForm(MethodType mt, MethodTypeImpl form);
- MethodType makeImpl(Class> rtype, Class>[] ptypes, boolean trusted);
- MethodTypeImpl newMethodTypeForm(MethodType mt);
- Invokers getInvokers(MethodType mt);
- void setInvokers(MethodType mt, Invokers inv);
- }
- public static void setMethodTypeFriend(Access token, MethodTypeFriend am) {
- Access.check(token);
- if (METHOD_TYPE_FRIEND != null)
- throw new InternalError(); // just once
- METHOD_TYPE_FRIEND = am;
- }
- static private MethodTypeFriend METHOD_TYPE_FRIEND;
-
- static MethodType makeImpl(Access token, Class> rtype, Class>[] ptypes, boolean trusted) {
- Access.check(token);
- return METHOD_TYPE_FRIEND.makeImpl(rtype, ptypes, trusted);
- }
-
- protected MethodTypeImpl(MethodType erasedType) {
+ protected MethodTypeForm(MethodType erasedType) {
this.erasedType = erasedType;
- Class>[] ptypes = METHOD_TYPE_FRIEND.ptypes(erasedType);
+ Class>[] ptypes = erasedType.ptypes();
int ptypeCount = ptypes.length;
int pslotCount = ptypeCount; // temp. estimate
int rtypeCount = 1; // temp. estimate
@@ -260,7 +230,7 @@ public class MethodTypeImpl {
* the type {@code (Object,int)Object} produces {@code null}.
*/
public static int[] primsAtEndOrder(MethodType mt) {
- MethodTypeImpl form = METHOD_TYPE_FRIEND.form(mt);
+ MethodTypeForm form = mt.form();
if (form.primsAtEnd == form.erasedType)
// quick check shows no reordering is necessary
return null;
@@ -273,7 +243,7 @@ public class MethodTypeImpl {
int lac = form.longPrimitiveParameterCount();
int rfill = 0, ifill = argc - pac, lfill = argc - lac;
- Class>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
+ Class>[] ptypes = mt.ptypes();
boolean changed = false;
for (int i = 0; i < ptypes.length; i++) {
Class> pt = ptypes[i];
@@ -300,7 +270,7 @@ public class MethodTypeImpl {
*/
public static MethodType reorderParameters(MethodType mt, int[] newParamOrder, Class>[] moreParams) {
if (newParamOrder == null) return mt; // no-op reordering
- Class>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
+ Class>[] ptypes = mt.ptypes();
Class>[] ntypes = new Class>[newParamOrder.length];
int maxParam = ptypes.length + (moreParams == null ? 0 : moreParams.length);
boolean changed = (ntypes.length != ptypes.length);
@@ -314,7 +284,7 @@ public class MethodTypeImpl {
ntypes[i] = nt;
}
if (!changed) return mt;
- return METHOD_TYPE_FRIEND.makeImpl(mt.returnType(), ntypes, true);
+ return MethodType.makeImpl(mt.returnType(), ntypes, true);
}
private static boolean hasTwoArgSlots(Class> type) {
@@ -376,28 +346,18 @@ public class MethodTypeImpl {
return slotToArgTable[argSlot] - 1;
}
- public static void initForm(Access token, MethodType mt) {
- Access.check(token);
- MethodTypeImpl form = findForm(mt);
- METHOD_TYPE_FRIEND.setForm(mt, form);
- if (form.erasedType == mt) {
- // This is a principal (erased) type; show it to the JVM.
- MethodHandleImpl.init(token, mt);
- }
- }
-
- static MethodTypeImpl findForm(MethodType mt) {
+ static MethodTypeForm findForm(MethodType mt) {
MethodType erased = canonicalize(mt, ERASE, ERASE);
if (erased == null) {
- // It is already erased. Make a new MethodTypeImpl.
- return METHOD_TYPE_FRIEND.newMethodTypeForm(mt);
+ // It is already erased. Make a new MethodTypeForm.
+ return new MethodTypeForm(mt);
} else {
- // Share the MethodTypeImpl with the erased version.
- return METHOD_TYPE_FRIEND.form(erased);
+ // Share the MethodTypeForm with the erased version.
+ return erased.form();
}
}
- /** Codes for {@link #canonicalize(java.lang.Class, int).
+ /** Codes for {@link #canonicalize(java.lang.Class, int)}.
* ERASE means change every reference to {@code Object}.
* WRAP means convert primitives (including {@code void} to their
* corresponding wrapper types. UNWRAP means the reverse of WRAP.
@@ -414,10 +374,10 @@ public class MethodTypeImpl {
* Otherwise return null.
*/
public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
- Class>[] ptypes = METHOD_TYPE_FRIEND.ptypes(mt);
- Class>[] ptc = MethodTypeImpl.canonicalizes(ptypes, howArgs);
+ Class>[] ptypes = mt.ptypes();
+ Class>[] ptc = MethodTypeForm.canonicalizes(ptypes, howArgs);
Class> rtype = mt.returnType();
- Class> rtc = MethodTypeImpl.canonicalize(rtype, howRet);
+ Class> rtc = MethodTypeForm.canonicalize(rtype, howRet);
if (ptc == null && rtc == null) {
// It is already canonical.
return null;
@@ -425,7 +385,7 @@ public class MethodTypeImpl {
// Find the erased version of the method type:
if (rtc == null) rtc = rtype;
if (ptc == null) ptc = ptypes;
- return METHOD_TYPE_FRIEND.makeImpl(rtc, ptc, true);
+ return MethodType.makeImpl(rtc, ptc, true);
}
/** Canonicalize the given return or param type.
@@ -496,16 +456,16 @@ public class MethodTypeImpl {
return cs;
}
- public static Invokers invokers(Access token, MethodType type) {
- Access.check(token);
- return invokers(type);
- }
- /*non-public*/ static Invokers invokers(MethodType type) {
- Invokers inv = METHOD_TYPE_FRIEND.getInvokers(type);
- if (inv != null) return inv;
- inv = new Invokers(type);
- METHOD_TYPE_FRIEND.setInvokers(type, inv);
- return inv;
+ /*non-public*/ void notifyGenericMethodType() {
+ if (genericInvoker != null) return;
+ try {
+ // Trigger adapter creation.
+ genericInvoker = InvokeGeneric.genericInvokerOf(erasedType);
+ } catch (Exception ex) {
+ Error err = new InternalError("Exception while resolving invokeGeneric");
+ err.initCause(ex);
+ throw err;
+ }
}
@Override
diff --git a/jdk/src/share/classes/java/dyn/MutableCallSite.java b/jdk/src/share/classes/java/lang/invoke/MutableCallSite.java
similarity index 99%
rename from jdk/src/share/classes/java/dyn/MutableCallSite.java
rename to jdk/src/share/classes/java/lang/invoke/MutableCallSite.java
index 95df7a6a6d1..fe18237bb38 100644
--- a/jdk/src/share/classes/java/dyn/MutableCallSite.java
+++ b/jdk/src/share/classes/java/lang/invoke/MutableCallSite.java
@@ -23,10 +23,8 @@
* questions.
*/
-package java.dyn;
+package java.lang.invoke;
-import sun.dyn.*;
-import sun.dyn.empty.Empty;
import java.util.concurrent.atomic.AtomicInteger;
/**
diff --git a/jdk/src/share/classes/sun/dyn/SpreadGeneric.java b/jdk/src/share/classes/java/lang/invoke/SpreadGeneric.java
similarity index 98%
rename from jdk/src/share/classes/sun/dyn/SpreadGeneric.java
rename to jdk/src/share/classes/java/lang/invoke/SpreadGeneric.java
index 4c6a0800bcc..a862723e025 100644
--- a/jdk/src/share/classes/sun/dyn/SpreadGeneric.java
+++ b/jdk/src/share/classes/java/lang/invoke/SpreadGeneric.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,14 +23,14 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
+import sun.invoke.util.ValueConversions;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
-import sun.dyn.util.ValueConversions;
-import static sun.dyn.MemberName.newIllegalArgumentException;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Generic spread adapter.
@@ -110,7 +110,7 @@ class SpreadGeneric {
static SpreadGeneric of(MethodType targetType, int spreadCount) {
if (targetType != targetType.generic())
throw new UnsupportedOperationException("NYI type="+targetType);
- MethodTypeImpl form = MethodTypeImpl.of(targetType);
+ MethodTypeForm form = targetType.form();
int outcount = form.parameterCount();
assert(spreadCount <= outcount);
SpreadGeneric[] spreadGens = form.spreadGeneric;
@@ -129,7 +129,7 @@ class SpreadGeneric {
// This mini-api is called from an Adapter to manage the spread.
/** A check/coercion that happens once before any selections. */
protected Object check(Object av, int n) {
- MethodHandleImpl.checkSpreadArgument(av, n);
+ checkSpreadArgument(av, n);
return av;
}
@@ -166,7 +166,7 @@ class SpreadGeneric {
// see if it has the required invoke method
MethodHandle entryPoint = null;
try {
- entryPoint = MethodHandleImpl.IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
+ entryPoint = IMPL_LOOKUP.findSpecial(acls, iname, entryType, acls);
} catch (ReflectiveOperationException ex) {
}
if (entryPoint == null) continue;
@@ -221,21 +221,21 @@ class SpreadGeneric {
@Override
public String toString() {
- return MethodHandleImpl.addTypeString(target, this);
+ return addTypeString(target, this);
}
static final MethodHandle NO_ENTRY = ValueConversions.identity();
protected boolean isPrototype() { return target == null; }
protected Adapter(SpreadGeneric outer) {
- super(Access.TOKEN, NO_ENTRY);
+ super(NO_ENTRY);
this.outer = outer;
this.target = null;
assert(isPrototype());
}
protected Adapter(SpreadGeneric outer, MethodHandle target) {
- super(Access.TOKEN, outer.entryPoint);
+ super(outer.entryPoint);
this.outer = outer;
this.target = target;
}
@@ -251,7 +251,7 @@ class SpreadGeneric {
return outer.select(av, n);
}
- static private final String CLASS_PREFIX; // "sun.dyn.SpreadGeneric$"
+ static private final String CLASS_PREFIX; // "java.lang.invoke.SpreadGeneric$"
static {
String aname = Adapter.class.getName();
String sname = Adapter.class.getSimpleName();
diff --git a/jdk/src/share/classes/java/dyn/SwitchPoint.java b/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java
similarity index 96%
rename from jdk/src/share/classes/java/dyn/SwitchPoint.java
rename to jdk/src/share/classes/java/lang/invoke/SwitchPoint.java
index 642e194b863..d81db187c88 100644
--- a/jdk/src/share/classes/java/dyn/SwitchPoint.java
+++ b/jdk/src/share/classes/java/lang/invoke/SwitchPoint.java
@@ -23,7 +23,7 @@
* questions.
*/
-package java.dyn;
+package java.lang.invoke;
/**
*
@@ -73,6 +73,10 @@ assertEquals("hodmet", (String) worker.invokeExact("met", "hod"));
* Switch points are useful without subclassing. They may also be subclassed.
* This may be useful in order to associate application-specific invalidation logic
* with the switch point.
+ * Notice that there is no permanent association between a switch point and
+ * the method handles it produces and consumes.
+ * The garbage collector may collect method handles produced or consumed
+ * by a switch point independently of the lifetime of the switch point itself.
*
* Implementation Note:
* A switch point behaves as if implemented on top of {@link MutableCallSite},
diff --git a/jdk/src/share/classes/sun/dyn/ToGeneric.java b/jdk/src/share/classes/java/lang/invoke/ToGeneric.java
similarity index 95%
rename from jdk/src/share/classes/sun/dyn/ToGeneric.java
rename to jdk/src/share/classes/java/lang/invoke/ToGeneric.java
index 38db3fea42f..22723975d5b 100644
--- a/jdk/src/share/classes/sun/dyn/ToGeneric.java
+++ b/jdk/src/share/classes/java/lang/invoke/ToGeneric.java
@@ -23,15 +23,14 @@
* questions.
*/
-package sun.dyn;
+package java.lang.invoke;
-import java.dyn.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
-import sun.dyn.util.ValueConversions;
-import sun.dyn.util.Wrapper;
-import static sun.dyn.MemberName.newIllegalArgumentException;
-import static sun.dyn.MethodTypeImpl.invokers;
+import sun.invoke.util.ValueConversions;
+import sun.invoke.util.Wrapper;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
/**
* Adapters which mediate between incoming calls which are not generic
@@ -73,7 +72,7 @@ class ToGeneric {
assert(entryType.erase() == entryType); // for now
// incoming call will first "forget" all reference types except Object
this.entryType = entryType;
- MethodHandle invoker0 = invokers(entryType.generic()).exactInvoker();
+ MethodHandle invoker0 = entryType.generic().invokers().exactInvoker();
MethodType rawEntryTypeInit;
Adapter ad = findAdapter(rawEntryTypeInit = entryType);
if (ad != null) {
@@ -89,15 +88,15 @@ class ToGeneric {
}
// next, it will reorder primitives after references
- MethodType primsAtEnd = MethodTypeImpl.of(entryType).primsAtEnd();
+ MethodType primsAtEnd = entryType.form().primsAtEnd();
// at the same time, it will "forget" all primitive types except int/long
- this.primsAtEndOrder = MethodTypeImpl.primsAtEndOrder(entryType);
+ this.primsAtEndOrder = MethodTypeForm.primsAtEndOrder(entryType);
if (primsAtEndOrder != null) {
// reordering is required; build on top of a simpler ToGeneric
ToGeneric va2 = ToGeneric.of(primsAtEnd);
this.adapter = va2.adapter;
if (true) throw new UnsupportedOperationException("NYI: primitive parameters must follow references; entryType = "+entryType);
- this.entryPoint = MethodHandleImpl.convertArguments(Access.TOKEN,
+ this.entryPoint = MethodHandleImpl.convertArguments(
va2.entryPoint, primsAtEnd, entryType, primsAtEndOrder);
// example: for entryType of (int,Object,Object), the reordered
// type is (Object,Object,int) and the order is {1,2,0},
@@ -107,7 +106,7 @@ class ToGeneric {
// after any needed argument reordering, it will reinterpret
// primitive arguments according to their "raw" types int/long
- MethodType intsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsInts();
+ MethodType intsAtEnd = primsAtEnd.form().primsAsInts();
ad = findAdapter(rawEntryTypeInit = intsAtEnd);
MethodHandle rawEntryPoint;
if (ad != null) {
@@ -116,7 +115,7 @@ class ToGeneric {
// Perhaps the adapter is available only for longs.
// If so, we can use it, but there will have to be a little
// more stack motion on each call.
- MethodType longsAtEnd = MethodTypeImpl.of(primsAtEnd).primsAsLongs();
+ MethodType longsAtEnd = primsAtEnd.form().primsAsLongs();
ad = findAdapter(rawEntryTypeInit = longsAtEnd);
if (ad != null) {
MethodType eptWithLongs = longsAtEnd.insertParameterTypes(0, ad.getClass());
@@ -128,7 +127,7 @@ class ToGeneric {
assert(midType.parameterType(i) == long.class);
assert(eptWithInts.parameterType(i) == int.class);
MethodType nextType = midType.changeParameterType(i, int.class);
- rawEntryPoint = MethodHandle.convertArguments(Access.TOKEN,
+ rawEntryPoint = MethodHandleImpl.convertArguments(
rawEntryPoint, nextType, midType, null);
midType = nextType;
}
@@ -143,7 +142,7 @@ class ToGeneric {
}
MethodType tepType = entryType.insertParameterTypes(0, ad.getClass());
this.entryPoint =
- AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, tepType, rawEntryPoint);
+ AdapterMethodHandle.makeRetypeRaw(tepType, rawEntryPoint);
if (this.entryPoint == null)
throw new UnsupportedOperationException("cannot retype to "+entryType
+" from "+rawEntryPoint.type().dropParameterTypes(0, 1));
@@ -168,7 +167,7 @@ class ToGeneric {
assert(src.isPrimitive() && dst.isPrimitive());
if (filteredInvoker == null) {
filteredInvoker =
- AdapterMethodHandle.makeCheckCast(Access.TOKEN,
+ AdapterMethodHandle.makeCheckCast(
invoker.type().generic(), invoker, 0, MethodHandle.class);
if (filteredInvoker == null) throw new UnsupportedOperationException("NYI");
}
@@ -177,7 +176,7 @@ class ToGeneric {
if (filteredInvoker == null) throw new InternalError();
}
if (filteredInvoker == null) return invoker;
- return AdapterMethodHandle.makeRetypeOnly(Access.TOKEN, invoker.type(), filteredInvoker);
+ return AdapterMethodHandle.makeRetypeOnly(invoker.type(), filteredInvoker);
}
/**
@@ -227,7 +226,7 @@ class ToGeneric {
// retype erased reference arguments (the cast makes it safe to do this)
MethodType tepType = type.insertParameterTypes(0, adapter.getClass());
MethodHandle typedEntryPoint =
- AdapterMethodHandle.makeRetypeRaw(Access.TOKEN, tepType, entryPoint);
+ AdapterMethodHandle.makeRetypeRaw(tepType, entryPoint);
return adapter.makeInstance(typedEntryPoint, invoker, convert, genericTarget);
}
@@ -248,7 +247,7 @@ class ToGeneric {
/** Return the adapter information for this type's erasure. */
static ToGeneric of(MethodType type) {
- MethodTypeImpl form = MethodTypeImpl.of(type);
+ MethodTypeForm form = type.form();
ToGeneric toGen = form.toGeneric;
if (toGen == null)
form.toGeneric = toGen = new ToGeneric(form.erasedType());
@@ -262,7 +261,7 @@ class ToGeneric {
/* Create an adapter for the given incoming call type. */
static Adapter findAdapter(MethodType entryPointType) {
- MethodTypeImpl form = MethodTypeImpl.of(entryPointType);
+ MethodTypeForm form = entryPointType.form();
Class> rtype = entryPointType.returnType();
int argc = form.parameterCount();
int lac = form.longPrimitiveParameterCount();
@@ -283,7 +282,7 @@ class ToGeneric {
for (String iname : inames) {
MethodHandle entryPoint = null;
try {
- entryPoint = MethodHandleImpl.IMPL_LOOKUP.
+ entryPoint = IMPL_LOOKUP.
findSpecial(acls, iname, entryPointType, acls);
} catch (ReflectiveOperationException ex) {
}
@@ -338,13 +337,13 @@ class ToGeneric {
@Override
public String toString() {
- return target == null ? "prototype:"+convert : MethodHandleImpl.addTypeString(target, this);
+ return target == null ? "prototype:"+convert : addTypeString(target, this);
}
protected boolean isPrototype() { return target == null; }
/* Prototype constructor. */
protected Adapter(MethodHandle entryPoint) {
- super(Access.TOKEN, entryPoint);
+ super(entryPoint);
this.invoker = null;
this.convert = entryPoint;
this.target = null;
@@ -356,7 +355,7 @@ class ToGeneric {
}
protected Adapter(MethodHandle entryPoint, MethodHandle invoker, MethodHandle convert, MethodHandle target) {
- super(Access.TOKEN, entryPoint);
+ super(entryPoint);
this.invoker = invoker;
this.convert = convert;
this.target = target;
@@ -396,7 +395,7 @@ class ToGeneric {
protected float return_F(Object res) throws Throwable { return (float) convert.invokeExact(res); }
protected double return_D(Object res) throws Throwable { return (double)convert.invokeExact(res); }
- static private final String CLASS_PREFIX; // "sun.dyn.ToGeneric$"
+ static private final String CLASS_PREFIX; // "java.lang.invoke.ToGeneric$"
static {
String aname = Adapter.class.getName();
String sname = Adapter.class.getSimpleName();
@@ -452,14 +451,15 @@ class genclasses {
static String[] TCHARS = { "L", "I", "J", "F", "D", "A" };
static String[][] TEMPLATES = { {
"@for@ arity=0..3 rcat<=4 nrefs<=99 nints<=99 nlongs<=99",
- "@for@ arity=4..5 rcat<=2 nrefs<=99 nints<=99 nlongs<=99",
+ "@for@ arity=4..4 rcat<=4 nrefs<=99 nints<=99 nlongs<=99",
+ "@for@ arity=5..5 rcat<=2 nrefs<=99 nints<=99 nlongs<=99",
"@for@ arity=6..10 rcat<=2 nrefs<=99 nints=0 nlongs<=99",
" //@each-cat@",
" static class @cat@ extends Adapter {",
" protected @cat@(MethodHandle entryPoint) { super(entryPoint); } // to build prototype",
" protected @cat@(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }",
" protected @cat@ makeInstance(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { return new @cat@(e, i, c, t); }",
- " protected Object target(@Ovav@) throws Throwable { return invoker.invokeExact(target, @av@); }",
+ " protected Object target(@Ovav@) throws Throwable { return invoker.invokeExact(target@comma@@av@); }",
" //@each-Tv@",
" protected Object target@cat@(@Tvav@) throws Throwable { return target(@av@); }",
" //@end-Tv@",
@@ -471,7 +471,7 @@ class genclasses {
" }",
} };
enum VAR {
- cat, R, Rc, Tv, av, Tvav, Ovav;
+ cat, R, Rc, Tv, av, comma, Tvav, Ovav;
public final String pattern = "@"+toString().replace('_','.')+"@";
public String binding;
static void makeBindings(boolean topLevel, int rcat, int nrefs, int nints, int nlongs) {
@@ -493,12 +493,13 @@ class genclasses {
}
VAR.Tv.binding = comma(Tv);
VAR.av.binding = comma(av);
+ VAR.comma.binding = (av.length == 0 ? "" : ", ");
VAR.Tvav.binding = comma(Tvav);
VAR.Ovav.binding = comma(Ovav);
}
static String arg(int i) { return "a"+i; }
static String param(String t, String a) { return t+" "+a; }
- static String comma(String[] v) { return comma(v, ""); }
+ static String comma(String[] v) { return comma("", v); }
static String comma(String sep, String[] v) {
if (v.length == 0) return "";
String res = sep+v[0];
@@ -735,7 +736,7 @@ class genclasses {
protected float invoke_F(long a0, long a1, long a2) throws Throwable { return return_F(targetA3(a0, a1, a2)); }
protected double invoke_D(long a0, long a1, long a2) throws Throwable { return return_D(targetA3(a0, a1, a2)); }
}
-//params=[4, 5, 2, 99, 99, 99]
+//params=[4, 4, 4, 99, 99, 99]
static class A4 extends Adapter {
protected A4(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A4(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
@@ -753,31 +754,50 @@ class genclasses {
protected Object invoke_L(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
+ protected float invoke_F(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
+ protected double invoke_D(Object a0, Object a1, Object a2, Object a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
+ protected float invoke_F(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
+ protected double invoke_D(Object a0, Object a1, Object a2, int a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, Object a1, int a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, Object a1, int a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, Object a1, int a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
+ protected float invoke_F(Object a0, Object a1, int a2, int a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
+ protected double invoke_D(Object a0, Object a1, int a2, int a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, int a1, int a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, int a1, int a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, int a1, int a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
+ protected float invoke_F(Object a0, int a1, int a2, int a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
+ protected double invoke_D(Object a0, int a1, int a2, int a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(int a0, int a1, int a2, int a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(int a0, int a1, int a2, int a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(int a0, int a1, int a2, int a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
+ protected float invoke_F(int a0, int a1, int a2, int a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
+ protected double invoke_D(int a0, int a1, int a2, int a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
+ protected float invoke_F(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
+ protected double invoke_D(Object a0, Object a1, Object a2, long a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, Object a1, long a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, Object a1, long a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, Object a1, long a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
+ protected float invoke_F(Object a0, Object a1, long a2, long a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
+ protected double invoke_D(Object a0, Object a1, long a2, long a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(Object a0, long a1, long a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(Object a0, long a1, long a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(Object a0, long a1, long a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
+ protected float invoke_F(Object a0, long a1, long a2, long a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
+ protected double invoke_D(Object a0, long a1, long a2, long a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
protected Object invoke_L(long a0, long a1, long a2, long a3) throws Throwable { return return_L(targetA4(a0, a1, a2, a3)); }
protected int invoke_I(long a0, long a1, long a2, long a3) throws Throwable { return return_I(targetA4(a0, a1, a2, a3)); }
protected long invoke_J(long a0, long a1, long a2, long a3) throws Throwable { return return_J(targetA4(a0, a1, a2, a3)); }
+ protected float invoke_F(long a0, long a1, long a2, long a3) throws Throwable { return return_F(targetA4(a0, a1, a2, a3)); }
+ protected double invoke_D(long a0, long a1, long a2, long a3) throws Throwable { return return_D(targetA4(a0, a1, a2, a3)); }
}
+//params=[5, 5, 2, 99, 99, 99]
static class A5 extends Adapter {
protected A5(MethodHandle entryPoint) { super(entryPoint); } // to build prototype
protected A5(MethodHandle e, MethodHandle i, MethodHandle c, MethodHandle t) { super(e, i, c, t); }
diff --git a/jdk/src/share/classes/java/dyn/VolatileCallSite.java b/jdk/src/share/classes/java/lang/invoke/VolatileCallSite.java
similarity index 99%
rename from jdk/src/share/classes/java/dyn/VolatileCallSite.java
rename to jdk/src/share/classes/java/lang/invoke/VolatileCallSite.java
index 616813ce2f5..de88f36bbb3 100644
--- a/jdk/src/share/classes/java/dyn/VolatileCallSite.java
+++ b/jdk/src/share/classes/java/lang/invoke/VolatileCallSite.java
@@ -23,9 +23,7 @@
* questions.
*/
-package java.dyn;
-
-import java.util.List;
+package java.lang.invoke;
/**
* A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
diff --git a/jdk/src/share/classes/java/dyn/WrongMethodTypeException.java b/jdk/src/share/classes/java/lang/invoke/WrongMethodTypeException.java
similarity index 96%
rename from jdk/src/share/classes/java/dyn/WrongMethodTypeException.java
rename to jdk/src/share/classes/java/lang/invoke/WrongMethodTypeException.java
index 2455432e858..7d538dc8096 100644
--- a/jdk/src/share/classes/java/dyn/WrongMethodTypeException.java
+++ b/jdk/src/share/classes/java/lang/invoke/WrongMethodTypeException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,7 +23,7 @@
* questions.
*/
-package java.dyn;
+package java.lang.invoke;
/**
* Thrown to indicate that code has attempted to call a method handle
diff --git a/jdk/src/share/classes/java/dyn/package-info.java b/jdk/src/share/classes/java/lang/invoke/package-info.java
similarity index 86%
rename from jdk/src/share/classes/java/dyn/package-info.java
rename to jdk/src/share/classes/java/lang/invoke/package-info.java
index d01c644f312..0eac856d218 100644
--- a/jdk/src/share/classes/java/dyn/package-info.java
+++ b/jdk/src/share/classes/java/lang/invoke/package-info.java
@@ -27,21 +27,18 @@
* The {@code java.lang.invoke} package contains dynamic language support provided directly by
* the Java core class libraries and virtual machine.
*
- *
- * Historic Note: In some early versions of Java SE 7,
- * the name of this package is {@code java.dyn}.
*
* Certain types in this package have special relations to dynamic
* language support in the virtual machine:
*
- * The class {@link java.dyn.MethodHandle MethodHandle} contains
+ * The class {@link java.lang.invoke.MethodHandle MethodHandle} contains
* signature polymorphic methods
* which can be linked regardless of their type descriptor.
* Normally, method linkage requires exact matching of type descriptors.
*
*
* The JVM bytecode format supports immediate constants of
- * the classes {@link java.dyn.MethodHandle MethodHandle} and {@link java.dyn.MethodType MethodType}.
+ * the classes {@link java.lang.invoke.MethodHandle MethodHandle} and {@link java.lang.invoke.MethodType MethodType}.
*
*
*
@@ -59,7 +56,7 @@
* with tag {@code CONSTANT_InvokeDynamic} (decimal 18). See below for its format.
* The entry specifies the following information:
*
- * a bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant)
+ * a bootstrap method (a {@link java.lang.invoke.MethodHandle MethodHandle} constant)
* the dynamic invocation name (a UTF8 string)
* the argument and return types of the call (encoded as a type descriptor in a UTF8 string)
* optionally, a sequence of additional static arguments to the bootstrap method ({@code ldc}-type constants)
@@ -75,11 +72,6 @@
* A dynamic call site is linked by means of a bootstrap method,
* as described below .
*
- *
- * Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType}
- * instead of a {@code CONSTANT_InvokeDynamic}. In earlier, obsolete versions of this API, the
- * bootstrap method was specified dynamically, in a per-class basis, during class initialization.
- *
*
constant pool entries for {@code invokedynamic} instructions
* If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 18),
* it must contain exactly four more bytes after the tag.
@@ -95,20 +87,20 @@
* except that the bootstrap method specifier reference replaces
* the {@code CONSTANT_Class} reference of a {@code CONSTANT_Methodref} entry.
*
- * constant pool entries for {@linkplain java.dyn.MethodType method types}
+ * constant pool entries for {@linkplain java.lang.invoke.MethodType method types}
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
* it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
* entry which represents a method type descriptor.
*
* The JVM will ensure that on first
- * execution of an {@code ldc} instruction for this entry, a {@link java.dyn.MethodType MethodType}
+ * execution of an {@code ldc} instruction for this entry, a {@link java.lang.invoke.MethodType MethodType}
* will be created which represents the type descriptor.
* Any classes mentioned in the {@code MethodType} will be loaded if necessary,
* but not initialized.
* Access checking and error reporting is performed exactly as it is for
* references by {@code ldc} instructions to {@code CONSTANT_Class} constants.
*
- *
constant pool entries for {@linkplain java.dyn.MethodHandle method handles}
+ * constant pool entries for {@linkplain java.lang.invoke.MethodHandle method handles}
* If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
* it must contain exactly three more bytes. The first byte after the tag is a subtag
* value which must be in the range 1 through 9, and the last two must be an index to a
@@ -119,7 +111,7 @@
* must agree according to the table below.
*
* The JVM will ensure that on first execution of an {@code ldc} instruction
- * for this entry, a {@link java.dyn.MethodHandle MethodHandle} will be created which represents
+ * for this entry, a {@link java.lang.invoke.MethodHandle MethodHandle} will be created which represents
* the field or method reference, according to the specific mode implied by the subtag.
*
* As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
@@ -135,23 +127,23 @@
*
* N subtag name member MH type bytecode behavior lookup expression
* 1 REF_getField C.f:T (C)T getfield C.f:T
- * {@linkplain java.dyn.MethodHandles.Lookup#findGetter findGetter(C.class,"f",T.class)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findGetter findGetter(C.class,"f",T.class)}
* 2 REF_getStatic C.f:T ( )T getstatic C.f:T
- * {@linkplain java.dyn.MethodHandles.Lookup#findStaticGetter findStaticGetter(C.class,"f",T.class)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticGetter findStaticGetter(C.class,"f",T.class)}
* 3 REF_putField C.f:T (C,T)void putfield C.f:T
- * {@linkplain java.dyn.MethodHandles.Lookup#findSetter findSetter(C.class,"f",T.class)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findSetter findSetter(C.class,"f",T.class)}
* 4 REF_putStatic C.f:T (T)void putstatic C.f:T
- * {@linkplain java.dyn.MethodHandles.Lookup#findStaticSetter findStaticSetter(C.class,"f",T.class)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findStaticSetter findStaticSetter(C.class,"f",T.class)}
* 5 REF_invokeVirtual C.m(A*)T (C,A*)T invokevirtual C.m(A*)T
- * {@linkplain java.dyn.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}
* 6 REF_invokeStatic C.m(A*)T (C,A*)T invokestatic C.m(A*)T
- * {@linkplain java.dyn.MethodHandles.Lookup#findStatic findStatic(C.class,"m",MT)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findStatic findStatic(C.class,"m",MT)}
* 7 REF_invokeSpecial C.m(A*)T (C,A*)T invokespecial C.m(A*)T
- * {@linkplain java.dyn.MethodHandles.Lookup#findSpecial findSpecial(C.class,"m",MT,this.class)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findSpecial findSpecial(C.class,"m",MT,this.class)}
* 8 REF_newInvokeSpecial C.<init>(A*)void (A*)C new C; dup; invokespecial C.<init>(A*)void
- * {@linkplain java.dyn.MethodHandles.Lookup#findConstructor findConstructor(C.class,MT)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findConstructor findConstructor(C.class,MT)}
* 9 REF_invokeInterface C.m(A*)T (C,A*)T invokeinterface C.m(A*)T
- * {@linkplain java.dyn.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#findVirtual findVirtual(C.class,"m",MT)}
*
*
* Here, the type {@code C} is taken from the {@code CONSTANT_Class} reference associated
@@ -169,7 +161,7 @@
* and returns the same result (if any) as the corresponding bytecode behavior .
*
* Each method handle constant also has an equivalent reflective lookup expression ,
- * which is a query to a method in {@link java.dyn.MethodHandles.Lookup}.
+ * which is a query to a method in {@link java.lang.invoke.MethodHandles.Lookup}.
* In the example lookup method expression given in the table above, the name {@code MT}
* stands for a {@code MethodType} built from {@code T} and the sequence of argument types {@code A*}.
* (Note that the type {@code C} is not prepended to the query type {@code MT} even if the member is non-static.)
@@ -191,7 +183,7 @@
* A constant may refer to a method or constructor with the {@code varargs}
* bit (hexadecimal {@code 0x0080}) set in its modifier bitmask.
* The method handle constant produced for such a method behaves as if
- * it were created by {@link java.dyn.MethodHandle#asVarargsCollector asVarargsCollector}.
+ * it were created by {@link java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector}.
* In other words, the constant method handle will exhibit variable arity,
* when invoked via {@code invokeGeneric}.
* On the other hand, its behavior with respect to {@code invokeExact} will be the same
@@ -225,7 +217,7 @@
* the call site must first be linked .
* Linking is accomplished by calling a bootstrap method
* which is given the static information content of the call site,
- * and which must produce a {@link java.dyn.MethodHandle method handle}
+ * and which must produce a {@link java.lang.invoke.MethodHandle method handle}
* that gives the behavior of the call site.
*
* Each {@code invokedynamic} instruction statically specifies its own
@@ -234,7 +226,7 @@
* just like {@code invokevirtual} and the other invoke instructions.
*
* Linking starts with resolving the constant pool entry for the
- * bootstrap method, and resolving a {@link java.dyn.MethodType MethodType} object for
+ * bootstrap method, and resolving a {@link java.lang.invoke.MethodType MethodType} object for
* the type descriptor of the dynamic call site.
* This resolution process may trigger class loading.
* It may therefore throw an error if a class fails to load.
@@ -251,8 +243,8 @@
*
optionally, one or more additional static arguments
*
* The method handle is then applied to the other values as if by
- * {@link java.dyn.MethodHandle#invokeGeneric invokeGeneric}.
- * The returned result must be a {@link java.dyn.CallSite CallSite} (or a subclass).
+ * {@link java.lang.invoke.MethodHandle#invokeGeneric invokeGeneric}.
+ * The returned result must be a {@link java.lang.invoke.CallSite CallSite} (or a subclass).
* The type of the call site's target must be exactly equal to the type
* derived from the dynamic call site's type descriptor and passed to
* the bootstrap method.
@@ -263,18 +255,12 @@
* For example, the first argument could be {@code Object}
* instead of {@code MethodHandles.Lookup}, and the return type
* could also be {@code Object} instead of {@code CallSite}.
- *
- * As with any method handle constant, a {@code varargs} modifier bit
- * on the bootstrap method is ignored.
- *
- * Note that the first argument of the bootstrap method cannot be
- * a simple {@code Class} reference. (This is a change from earlier
- * versions of this specification. If the caller class is needed,
- * it is easy to {@linkplain java.dyn.MethodHandles.Lookup#lookupClass() extract it}
- * from the {@code Lookup} object.)
+ * (Note that the types and number of the stacked arguments limit
+ * the legal kinds of bootstrap methods to appropriately typed
+ * static methods and constructors of {@code CallSite} subclasses.)
*
* After resolution, the linkage process may fail in a variety of ways.
- * All failures are reported by an {@link java.dyn.InvokeDynamicBootstrapError InvokeDynamicBootstrapError},
+ * All failures are reported by a {@link java.lang.BootstrapMethodError BootstrapMethodError},
* which is thrown as the abnormal termination of the dynamic call
* site execution.
* The following circumstances will cause this:
@@ -290,7 +276,7 @@
*
the bootstrap method has a wrong argument or return type
* the bootstrap method invocation completes abnormally
* the result from the bootstrap invocation is not a reference to
- * an object of type {@link java.dyn.CallSite CallSite}
+ * an object of type {@link java.lang.invoke.CallSite CallSite}
* the target of the {@code CallSite} does not have a target of
* the expected {@code MethodType}
*
@@ -309,7 +295,7 @@
*
* In an application which requires dynamic call sites with individually
* mutable behaviors, their bootstrap methods should produce distinct
- * {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
+ * {@link java.lang.invoke.CallSite CallSite} objects, one for each linkage request.
* Alternatively, an application can link a single {@code CallSite} object
* to several {@code invokedynamic} instructions, in which case
* a change to the target method will become visible at each of
@@ -322,11 +308,12 @@
* chosen target object.
*
*
- * Historic Note: Unlike some previous versions of this specification,
- * these rules do not enable the JVM to duplicate dynamic call sites,
+ * Discussion:
+ * These rules do not enable the JVM to duplicate dynamic call sites,
* or to issue “causeless” bootstrap method calls.
* Every dynamic call site transitions at most once from unlinked to linked,
* just before its first invocation.
+ * There is no way to undo the effect of a completed bootstrap method call.
*
*
* Each {@code CONSTANT_InvokeDynamic} entry contains an index which references
@@ -354,7 +341,7 @@
*
* An {@code invokedynamic} instruction specifies at least three arguments
* to pass to its bootstrap method:
- * The caller class (expressed as a {@link java.dyn.MethodHandles.Lookup Lookup object},
+ * The caller class (expressed as a {@link java.lang.invoke.MethodHandles.Lookup Lookup object},
* the name (extracted from the {@code CONSTANT_NameAndType} entry),
* and the type (also extracted from the {@code CONSTANT_NameAndType} entry).
* The {@code invokedynamic} instruction may specify additional metadata values
@@ -382,8 +369,8 @@
* CONSTANT_Long java.lang.Longthe indexed long value
* CONSTANT_Float java.lang.Floatthe indexed float value
* CONSTANT_Double java.lang.Doublethe indexed double value
- * CONSTANT_MethodHandle java.dyn.MethodHandlethe indexed method handle constant
- * CONSTANT_MethodType java.dyn.MethodTypethe indexed method type constant
+ * CONSTANT_MethodHandle java.lang.invoke.MethodHandlethe indexed method handle constant
+ * CONSTANT_MethodType java.lang.invoke.MethodTypethe indexed method type constant
*
*
*
@@ -403,7 +390,7 @@
* then some or all of the arguments specified here may be collected into a trailing array parameter.
* (This is not a special rule, but rather a useful consequence of the interaction
* between {@code CONSTANT_MethodHandle} constants, the modifier bit for variable arity methods,
- * and the {@code java.dyn.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
+ * and the {@code java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector} transformation.)
*
* Given these rules, here are examples of legal bootstrap method declarations,
* given various numbers {@code N} of extra arguments.
@@ -436,7 +423,7 @@
* constant as an {@code Object}, but the type matching machinery of {@code invokeGeneric}
* will cast the reference back to {@code MethodHandle} before invoking the bootstrap method.
* (If a string constant were passed instead, by badly generated code, that cast would then fail,
- * resulting in an {@code InvokeDynamicBootstrapError}.)
+ * resulting in a {@code BootstrapMethodError}.)
*
* Extra bootstrap method arguments are intended to allow language implementors
* to safely and compactly encode metadata.
@@ -473,6 +460,7 @@ struct BootstrapMethods_attr {
*
*
* @author John Rose, JSR 292 EG
+ * @since 1.7
*/
-package java.dyn;
+package java.lang.invoke;
diff --git a/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java b/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java
index 522fa3956b9..004cd408110 100644
--- a/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java
+++ b/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java
@@ -28,6 +28,7 @@ import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Enumeration;
+import sun.net.ResourceManager;
/**
* Abstract datagram and multicast socket implementation base class.
@@ -66,7 +67,14 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl
*/
protected synchronized void create() throws SocketException {
fd = new FileDescriptor();
- datagramSocketCreate();
+ ResourceManager.beforeUdpCreate();
+ try {
+ datagramSocketCreate();
+ } catch (SocketException ioe) {
+ ResourceManager.afterUdpClose();
+ fd = null;
+ throw ioe;
+ }
}
/**
@@ -211,6 +219,7 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl
protected void close() {
if (fd != null) {
datagramSocketClose();
+ ResourceManager.afterUdpClose();
fd = null;
}
}
diff --git a/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java b/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java
index 6d73cbc242c..f61fb34bdf1 100644
--- a/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java
+++ b/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java
@@ -32,6 +32,7 @@ import java.io.FileDescriptor;
import sun.net.ConnectionResetException;
import sun.net.NetHooks;
+import sun.net.ResourceManager;
/**
* Default Socket Implementation. This implementation does
@@ -68,6 +69,10 @@ abstract class AbstractPlainSocketImpl extends SocketImpl
private int resetState;
private final Object resetLock = new Object();
+ /* whether this Socket is a stream (TCP) socket or not (UDP)
+ */
+ private boolean stream;
+
/**
* Load net library into runtime.
*/
@@ -82,7 +87,19 @@ abstract class AbstractPlainSocketImpl extends SocketImpl
*/
protected synchronized void create(boolean stream) throws IOException {
fd = new FileDescriptor();
- socketCreate(stream);
+ this.stream = stream;
+ if (!stream) {
+ ResourceManager.beforeUdpCreate();
+ try {
+ socketCreate(false);
+ } catch (IOException ioe) {
+ ResourceManager.afterUdpClose();
+ fd = null;
+ throw ioe;
+ }
+ } else {
+ socketCreate(true);
+ }
if (socket != null)
socket.setCreated();
if (serverSocket != null)
@@ -479,6 +496,9 @@ abstract class AbstractPlainSocketImpl extends SocketImpl
protected void close() throws IOException {
synchronized(fdLock) {
if (fd != null) {
+ if (!stream) {
+ ResourceManager.afterUdpClose();
+ }
if (fdUseCount == 0) {
if (closePending) {
return;
diff --git a/jdk/src/share/classes/java/net/URI.java b/jdk/src/share/classes/java/net/URI.java
index 3465e1ab879..d1d9a87189a 100644
--- a/jdk/src/share/classes/java/net/URI.java
+++ b/jdk/src/share/classes/java/net/URI.java
@@ -1829,21 +1829,23 @@ public final class URI
} else if (authority != null) {
sb.append("//");
if (authority.startsWith("[")) {
+ // authority should (but may not) contain an embedded IPv6 address
int end = authority.indexOf("]");
- if (end != -1 && authority.indexOf(":")!=-1) {
- String doquote, dontquote;
+ String doquote = authority, dontquote = "";
+ if (end != -1 && authority.indexOf(":") != -1) {
+ // the authority contains an IPv6 address
if (end == authority.length()) {
dontquote = authority;
doquote = "";
} else {
- dontquote = authority.substring(0,end+1);
- doquote = authority.substring(end+1);
+ dontquote = authority.substring(0 , end + 1);
+ doquote = authority.substring(end + 1);
}
- sb.append (dontquote);
- sb.append(quote(doquote,
+ }
+ sb.append(dontquote);
+ sb.append(quote(doquote,
L_REG_NAME | L_SERVER,
H_REG_NAME | H_SERVER));
- }
} else {
sb.append(quote(authority,
L_REG_NAME | L_SERVER,
diff --git a/jdk/src/share/classes/java/net/URLConnection.java b/jdk/src/share/classes/java/net/URLConnection.java
index 6db1f6e82b3..976e8f66cea 100644
--- a/jdk/src/share/classes/java/net/URLConnection.java
+++ b/jdk/src/share/classes/java/net/URLConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2011, 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
@@ -1422,7 +1422,7 @@ public abstract class URLConnection {
if (!is.markSupported())
return null;
- is.mark(12);
+ is.mark(16);
int c1 = is.read();
int c2 = is.read();
int c3 = is.read();
@@ -1434,6 +1434,11 @@ public abstract class URLConnection {
int c9 = is.read();
int c10 = is.read();
int c11 = is.read();
+ int c12 = is.read();
+ int c13 = is.read();
+ int c14 = is.read();
+ int c15 = is.read();
+ int c16 = is.read();
is.reset();
if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
@@ -1461,6 +1466,13 @@ public abstract class URLConnection {
}
}
+ // big and little (identical) endian UTF-8 encodings, with BOM
+ if (c1 == 0xef && c2 == 0xbb && c3 == 0xbf) {
+ if (c4 == '<' && c5 == '?' && c6 == 'x') {
+ return "application/xml";
+ }
+ }
+
// big and little endian UTF-16 encodings, with byte order mark
if (c1 == 0xfe && c2 == 0xff) {
if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' &&
@@ -1476,6 +1488,23 @@ public abstract class URLConnection {
}
}
+ // big and little endian UTF-32 encodings, with BOM
+ if (c1 == 0x00 && c2 == 0x00 && c3 == 0xfe && c4 == 0xff) {
+ if (c5 == 0 && c6 == 0 && c7 == 0 && c8 == '<' &&
+ c9 == 0 && c10 == 0 && c11 == 0 && c12 == '?' &&
+ c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') {
+ return "application/xml";
+ }
+ }
+
+ if (c1 == 0xff && c2 == 0xfe && c3 == 0x00 && c4 == 0x00) {
+ if (c5 == '<' && c6 == 0 && c7 == 0 && c8 == 0 &&
+ c9 == '?' && c10 == 0 && c11 == 0 && c12 == 0 &&
+ c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) {
+ return "application/xml";
+ }
+ }
+
if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
return "image/gif";
}
diff --git a/jdk/src/share/classes/java/nio/file/Files.java b/jdk/src/share/classes/java/nio/file/Files.java
index 3e19ca3e515..8b7af13544c 100644
--- a/jdk/src/share/classes/java/nio/file/Files.java
+++ b/jdk/src/share/classes/java/nio/file/Files.java
@@ -1712,10 +1712,10 @@ public final class Files {
* @return the {@code path} parameter
*
* @throws UnsupportedOperationException
- * if the attribute view is not available or it does not support
- * updating the attribute
+ * if the attribute view is not available
* @throws IllegalArgumentException
- * if the attribute value is of the correct type but has an
+ * if the attribute name is not specified, or is not recognized, or
+ * the attribute value is of the correct type but has an
* inappropriate value
* @throws ClassCastException
* if the attribute value is not of the expected type or is a
@@ -1776,9 +1776,12 @@ public final class Files {
* @param options
* options indicating how symbolic links are handled
*
- * @return the attribute value or {@code null} if the attribute view
- * is not available or it does not support reading the attribute
+ * @return the attribute value
*
+ * @throws UnsupportedOperationException
+ * if the attribute view is not available
+ * @throws IllegalArgumentException
+ * if the attribute name is not specified or is not recognized
* @throws IOException
* if an I/O error occurs
* @throws SecurityException
@@ -1794,8 +1797,9 @@ public final class Files {
{
// only one attribute should be read
if (attribute.indexOf('*') >= 0 || attribute.indexOf(',') >= 0)
- return null;
+ throw new IllegalArgumentException(attribute);
Map map = readAttributes(path, attribute, options);
+ assert map.size() == 1;
String name;
int pos = attribute.indexOf(':');
if (pos == -1) {
@@ -1868,9 +1872,14 @@ public final class Files {
* @param options
* options indicating how symbolic links are handled
*
- * @return a map of the attributes returned; may be empty. The map's keys
- * are the attribute names, its values are the attribute values
+ * @return a map of the attributes returned; The map's keys are the
+ * attribute names, its values are the attribute values
*
+ * @throws UnsupportedOperationException
+ * if the attribute view is not available
+ * @throws IllegalArgumentException
+ * if no attributes are specified or an unrecognized attributes is
+ * specified
* @throws IOException
* if an I/O error occurs
* @throws SecurityException
diff --git a/jdk/src/share/classes/java/nio/file/Path.java b/jdk/src/share/classes/java/nio/file/Path.java
index 85436b01d9a..618f0226363 100644
--- a/jdk/src/share/classes/java/nio/file/Path.java
+++ b/jdk/src/share/classes/java/nio/file/Path.java
@@ -228,6 +228,9 @@ public interface Path
* not have a root component and the given path has a root component then
* this path does not start with the given path.
*
+ * If the given path is associated with a different {@code FileSystem}
+ * to this path then {@code false} is returned.
+ *
* @param other
* the given path
*
@@ -270,6 +273,9 @@ public interface Path
* does not have a root component and the given path has a root component
* then this path does not end with the given path.
*
+ *
If the given path is associated with a different {@code FileSystem}
+ * to this path then {@code false} is returned.
+ *
* @param other
* the given path
*
@@ -283,7 +289,10 @@ public interface Path
* the given path string, in exactly the manner specified by the {@link
* #endsWith(Path) endsWith(Path)} method. On UNIX for example, the path
* "{@code foo/bar}" ends with "{@code foo/bar}" and "{@code bar}". It does
- * not end with "{@code r}" or "{@code /bar}".
+ * not end with "{@code r}" or "{@code /bar}". Note that trailing separators
+ * are not taken into account, and so invoking this method on the {@code
+ * Path}"{@code foo/bar}" with the {@code String} "{@code bar/}" returns
+ * {@code true}.
*
* @param other
* the given path string
@@ -724,12 +733,18 @@ public interface Path
* provider, platform specific. This method does not access the file system
* and neither file is required to exist.
*
+ *
This method may not be used to compare paths that are associated
+ * with different file system providers.
+ *
* @param other the path compared to this path.
*
* @return zero if the argument is {@link #equals equal} to this path, a
* value less than zero if this path is lexicographically less than
* the argument, or a value greater than zero if this path is
* lexicographically greater than the argument
+ *
+ * @throws ClassCastException
+ * if the paths are associated with different providers
*/
@Override
int compareTo(Path other);
@@ -738,7 +753,7 @@ public interface Path
* Tests this path for equality with the given object.
*
*
If the given object is not a Path, or is a Path associated with a
- * different provider, then this method immediately returns {@code false}.
+ * different {@code FileSystem}, then this method returns {@code false}.
*
*
Whether or not two path are equal depends on the file system
* implementation. In some cases the paths are compared without regard
diff --git a/jdk/src/share/classes/java/nio/file/WatchKey.java b/jdk/src/share/classes/java/nio/file/WatchKey.java
index 23897dba454..83403e96a3b 100644
--- a/jdk/src/share/classes/java/nio/file/WatchKey.java
+++ b/jdk/src/share/classes/java/nio/file/WatchKey.java
@@ -146,5 +146,5 @@ public interface WatchKey {
*
* @return the object for which this watch key was created
*/
- //T watchable();
+ Watchable watchable();
}
diff --git a/jdk/src/share/classes/java/nio/file/attribute/FileTime.java b/jdk/src/share/classes/java/nio/file/attribute/FileTime.java
index 6cac437cdce..4e77b0e0172 100644
--- a/jdk/src/share/classes/java/nio/file/attribute/FileTime.java
+++ b/jdk/src/share/classes/java/nio/file/attribute/FileTime.java
@@ -216,12 +216,14 @@ public final class FileTime
* "2009-02-13T23:31:30Z"}, and {@code FileTime.fromMillis(1234567890123L).toString()}
* yields {@code "2009-02-13T23:31:30.123Z"}.
*
- *
A {@code FileTime} is primarly intended to represent the value of a
+ *
A {@code FileTime} is primarily intended to represent the value of a
* file's time stamp. Where used to represent extreme values , where
* the year is less than "{@code 0001}" or greater than "{@code 9999}" then
- * the year may be expanded to more than four digits and may be
- * negative-signed. If more than four digits then leading zeros are not
- * present. The year before "{@code 0001}" is "{@code -0001}".
+ * this method deviates from ISO 8601 in the same manner as the
+ * XML Schema
+ * language . That is, the year may be expanded to more than four digits
+ * and may be negative-signed. If more than four digits then leading zeros
+ * are not present. The year before "{@code 0001}" is "{@code -0001}".
*
* @return the string representation of this file time
*/
diff --git a/jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java b/jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java
index ad285bd6ddb..8d43fb93769 100644
--- a/jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java
+++ b/jdk/src/share/classes/java/nio/file/spi/FileSystemProvider.java
@@ -1037,6 +1037,11 @@ public abstract class FileSystemProvider {
* @return a map of the attributes returned; may be empty. The map's keys
* are the attribute names, its values are the attribute values
*
+ * @throws UnsupportedOperationException
+ * if the attribute view is not available
+ * @throws IllegalArgumentException
+ * if no attributes are specified or an unrecognized attributes is
+ * specified
* @throws IOException
* If an I/O error occurs
* @throws SecurityException
@@ -1064,10 +1069,10 @@ public abstract class FileSystemProvider {
* options indicating how symbolic links are handled
*
* @throws UnsupportedOperationException
- * if the attribute view is not available or it does not support
- * updating the attribute
+ * if the attribute view is not available
* @throws IllegalArgumentException
- * if the attribute value is of the correct type but has an
+ * if the attribute name is not specified, or is not recognized, or
+ * the attribute value is of the correct type but has an
* inappropriate value
* @throws ClassCastException
* If the attribute value is not of the expected type or is a
diff --git a/jdk/src/share/classes/java/security/AccessControlContext.java b/jdk/src/share/classes/java/security/AccessControlContext.java
index e80953b6696..940aff63770 100644
--- a/jdk/src/share/classes/java/security/AccessControlContext.java
+++ b/jdk/src/share/classes/java/security/AccessControlContext.java
@@ -29,6 +29,9 @@ import java.util.ArrayList;
import java.util.List;
import sun.security.util.Debug;
import sun.security.util.SecurityConstants;
+import sun.misc.JavaSecurityAccess;
+import sun.misc.SharedSecrets;
+
/**
* An AccessControlContext is used to make system resource access decisions
@@ -196,6 +199,24 @@ public final class AccessControlContext {
this.isPrivileged = isPrivileged;
}
+ /**
+ * Constructor for JavaSecurityAccess.doIntersectionPrivilege()
+ */
+ AccessControlContext(ProtectionDomain[] context,
+ AccessControlContext privilegedContext)
+ {
+ this.context = context;
+ this.privilegedContext = privilegedContext;
+ this.isPrivileged = true;
+ }
+
+ /**
+ * Returns this context's context.
+ */
+ ProtectionDomain[] getContext() {
+ return context;
+ }
+
/**
* Returns true if this context is privileged.
*/
diff --git a/jdk/src/share/classes/java/security/CodeSource.java b/jdk/src/share/classes/java/security/CodeSource.java
index 5ec8cebc028..b821a4ec9c1 100644
--- a/jdk/src/share/classes/java/security/CodeSource.java
+++ b/jdk/src/share/classes/java/security/CodeSource.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2011, 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
@@ -578,7 +578,7 @@ public class CodeSource implements java.io.Serializable {
// Deserialize array of code signers (if any)
try {
- this.signers = (CodeSigner[])ois.readObject();
+ this.signers = ((CodeSigner[])ois.readObject()).clone();
} catch (IOException ioe) {
// no signers present
}
diff --git a/jdk/src/share/classes/java/security/ProtectionDomain.java b/jdk/src/share/classes/java/security/ProtectionDomain.java
index 43a39028e3d..9025e81b5dc 100644
--- a/jdk/src/share/classes/java/security/ProtectionDomain.java
+++ b/jdk/src/share/classes/java/security/ProtectionDomain.java
@@ -36,6 +36,8 @@ import static sun.misc.JavaSecurityProtectionDomainAccess.ProtectionDomainCache;
import sun.misc.SharedSecrets;
import sun.security.util.Debug;
import sun.security.util.SecurityConstants;
+import sun.misc.JavaSecurityAccess;
+import sun.misc.SharedSecrets;
/**
*
@@ -59,6 +61,36 @@ import sun.security.util.SecurityConstants;
public class ProtectionDomain {
+ static {
+ // Set up JavaSecurityAccess in SharedSecrets
+ SharedSecrets.setJavaSecurityAccess(
+ new JavaSecurityAccess() {
+ public T doIntersectionPrivilege(
+ PrivilegedAction action,
+ final AccessControlContext stack,
+ final AccessControlContext context)
+ {
+ if (action == null) {
+ throw new NullPointerException();
+ }
+ return AccessController.doPrivileged(
+ action,
+ new AccessControlContext(
+ stack.getContext(), context).optimize()
+ );
+ }
+
+ public T doIntersectionPrivilege(
+ PrivilegedAction action,
+ AccessControlContext context)
+ {
+ return doIntersectionPrivilege(action,
+ AccessController.getContext(), context);
+ }
+ }
+ );
+ }
+
/* CodeSource */
private CodeSource codesource ;
diff --git a/jdk/src/share/classes/java/security/Timestamp.java b/jdk/src/share/classes/java/security/Timestamp.java
index 1629d9bbff9..f66d2883e62 100644
--- a/jdk/src/share/classes/java/security/Timestamp.java
+++ b/jdk/src/share/classes/java/security/Timestamp.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011, 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
@@ -157,7 +157,8 @@ public final class Timestamp implements Serializable {
// Explicitly reset hash code value to -1
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
- ois.defaultReadObject();
- myhash = -1;
+ ois.defaultReadObject();
+ myhash = -1;
+ timestamp = new Date(timestamp.getTime());
}
}
diff --git a/jdk/src/share/classes/java/sql/DriverManager.java b/jdk/src/share/classes/java/sql/DriverManager.java
index 15273877dba..ce6c6bf4823 100644
--- a/jdk/src/share/classes/java/sql/DriverManager.java
+++ b/jdk/src/share/classes/java/sql/DriverManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2011, 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
@@ -26,10 +26,10 @@
package java.sql;
import java.util.Iterator;
-import java.sql.Driver;
import java.util.ServiceLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.concurrent.CopyOnWriteArrayList;
/**
@@ -79,6 +79,27 @@ import java.security.PrivilegedAction;
public class DriverManager {
+ // List of registered JDBC drivers
+ private final static CopyOnWriteArrayList registeredDrivers = new CopyOnWriteArrayList();
+ private static volatile int loginTimeout = 0;
+ private static volatile java.io.PrintWriter logWriter = null;
+ private static volatile java.io.PrintStream logStream = null;
+ // Used in println() to synchronize logWriter
+ private final static Object logSync = new Object();
+
+ /* Prevent the DriverManager class from being instantiated. */
+ private DriverManager(){}
+
+
+ /**
+ * Load the initial JDBC drivers by checking the System property
+ * jdbc.properties and then use the {@code ServiceLoader} mechanism
+ */
+ static {
+ loadInitialDrivers();
+ println("JDBC DriverManager initialized");
+ }
+
/**
* The SQLPermission constant that allows the
* setting of the logging stream.
@@ -235,44 +256,33 @@ public class DriverManager {
*/
public static Driver getDriver(String url)
throws SQLException {
- java.util.Vector drivers = null;
println("DriverManager.getDriver(\"" + url + "\")");
- if (!initialized) {
- initialize();
- }
-
- synchronized (DriverManager.class){
- // use the read copy of the drivers vector
- drivers = readDrivers;
- }
-
// Gets the classloader of the code that called this method, may
// be null.
ClassLoader callerCL = DriverManager.getCallerClassLoader();
- // Walk through the loaded drivers attempting to locate someone
+ // Walk through the loaded registeredDrivers attempting to locate someone
// who understands the given URL.
- for (int i = 0; i < drivers.size(); i++) {
- DriverInfo di = (DriverInfo)drivers.elementAt(i);
+ for (Driver aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
- if ( getCallerClass(callerCL, di.driverClassName ) !=
- di.driverClass ) {
- println(" skipping: " + di);
- continue;
- }
- try {
- println(" trying " + di);
- if (di.driver.acceptsURL(url)) {
- // Success!
- println("getDriver returning " + di);
- return (di.driver);
+ if(isDriverAllowed(aDriver, callerCL)) {
+ try {
+ if(aDriver.acceptsURL(url)) {
+ // Success!
+ println("getDriver returning " + aDriver.getClass().getName());
+ return (aDriver);
+ }
+
+ } catch(SQLException sqe) {
+ // Drop through and try the next driver.
}
- } catch (SQLException ex) {
- // Drop through and try the next driver.
+ } else {
+ println(" skipping: " + aDriver.getClass().getName());
}
+
}
println("getDriver: no suitable driver");
@@ -292,23 +302,16 @@ public class DriverManager {
*/
public static synchronized void registerDriver(java.sql.Driver driver)
throws SQLException {
- if (!initialized) {
- initialize();
+
+ /* Register the driver if it has not already been added to our list */
+ if(driver != null) {
+ registeredDrivers.addIfAbsent(driver);
+ } else {
+ // This is for compatibility with the original DriverManager
+ throw new NullPointerException();
}
- DriverInfo di = new DriverInfo();
-
- di.driver = driver;
- di.driverClass = driver.getClass();
- di.driverClassName = di.driverClass.getName();
-
- // Not Required -- drivers.addElement(di);
-
- writeDrivers.addElement(di);
- println("registerDriver: " + di);
-
- /* update the read copy of drivers vector */
- readDrivers = (java.util.Vector) writeDrivers.clone();
+ println("registerDriver: " + driver);
}
@@ -321,37 +324,26 @@ public class DriverManager {
*/
public static synchronized void deregisterDriver(Driver driver)
throws SQLException {
+ if (driver == null) {
+ return;
+ }
+
// Gets the classloader of the code that called this method,
// may be null.
ClassLoader callerCL = DriverManager.getCallerClassLoader();
println("DriverManager.deregisterDriver: " + driver);
- // Walk through the loaded drivers.
- int i;
- DriverInfo di = null;
- for (i = 0; i < writeDrivers.size(); i++) {
- di = (DriverInfo)writeDrivers.elementAt(i);
- if (di.driver == driver) {
- break;
+ if(registeredDrivers.contains(driver)) {
+ if (isDriverAllowed(driver, callerCL)) {
+ registeredDrivers.remove(driver);
+ } else {
+ // If the caller does not have permission to load the driver then
+ // throw a SecurityException.
+ throw new SecurityException();
}
- }
- // If we can't find the driver just return.
- if (i >= writeDrivers.size()) {
+ } else {
println(" couldn't find driver to unload");
- return;
}
-
- // If the caller does not have permission to load the driver then
- // throw a security exception.
- if (getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
- throw new SecurityException();
- }
-
- // Remove the driver. Other entries in drivers get shuffled down.
- writeDrivers.removeElementAt(i);
-
- /* update the read copy of drivers vector */
- readDrivers = (java.util.Vector) writeDrivers.clone();
}
/**
@@ -364,34 +356,22 @@ public class DriverManager {
* @return the list of JDBC Drivers loaded by the caller's class loader
*/
public static java.util.Enumeration getDrivers() {
- java.util.Vector result = new java.util.Vector<>();
- java.util.Vector drivers = null;
-
- if (!initialized) {
- initialize();
- }
-
- synchronized (DriverManager.class){
- // use the readcopy of drivers
- drivers = readDrivers;
- }
+ java.util.Vector result = new java.util.Vector();
// Gets the classloader of the code that called this method, may
// be null.
ClassLoader callerCL = DriverManager.getCallerClassLoader();
- // Walk through the loaded drivers.
- for (int i = 0; i < drivers.size(); i++) {
- DriverInfo di = (DriverInfo)drivers.elementAt(i);
+ // Walk through the loaded registeredDrivers.
+ for(Driver aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
- if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
- println(" skipping: " + di);
- continue;
+ if(isDriverAllowed(aDriver, callerCL)) {
+ result.addElement(aDriver);
+ } else {
+ println(" skipping: " + aDriver.getClass().getName());
}
- result.addElement(di.driver);
}
-
return (result.elements());
}
@@ -481,21 +461,22 @@ public class DriverManager {
//------------------------------------------------------------------------
- // Returns the class object that would be created if the code calling the
- // driver manager had loaded the driver class, or null if the class
- // is inaccessible.
- private static Class getCallerClass(ClassLoader callerClassLoader,
- String driverClassName) {
- Class callerC = null;
+ // Indicates whether the class object that would be created if the code calling
+ // DriverManager is accessible.
+ private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
+ boolean result = false;
+ if(driver != null) {
+ Class> aClass = null;
+ try {
+ aClass = Class.forName(driver.getClass().getName(), true, classLoader);
+ } catch (Exception ex) {
+ result = false;
+ }
- try {
- callerC = Class.forName(driverClassName, true, callerClassLoader);
- }
- catch (Exception ex) {
- callerC = null; // being very careful
+ result = ( aClass == driver.getClass() ) ? true : false;
}
- return callerC;
+ return result;
}
private static void loadInitialDrivers() {
@@ -544,26 +525,17 @@ public class DriverManager {
});
println("DriverManager.initialize: jdbc.drivers = " + drivers);
- if (drivers == null) {
+
+ if (drivers == null || drivers.equals("")) {
return;
}
- while (drivers.length() != 0) {
- int x = drivers.indexOf(':');
- String driver;
- if (x < 0) {
- driver = drivers;
- drivers = "";
- } else {
- driver = drivers.substring(0, x);
- drivers = drivers.substring(x+1);
- }
- if (driver.length() == 0) {
- continue;
- }
+ String[] driversList = drivers.split(":");
+ println("number of Drivers:" + driversList.length);
+ for (String aDriver : driversList) {
try {
- println("DriverManager.Initialize: loading " + driver);
- Class.forName(driver, true,
- ClassLoader.getSystemClassLoader());
+ println("DriverManager.Initialize: loading " + aDriver);
+ Class.forName(aDriver, true,
+ ClassLoader.getSystemClassLoader());
} catch (Exception ex) {
println("DriverManager.Initialize: load failed: " + ex);
}
@@ -574,7 +546,6 @@ public class DriverManager {
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
- java.util.Vector drivers = null;
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
@@ -594,40 +565,32 @@ public class DriverManager {
println("DriverManager.getConnection(\"" + url + "\")");
- if (!initialized) {
- initialize();
- }
-
- synchronized (DriverManager.class){
- // use the readcopy of drivers
- drivers = readDrivers;
- }
-
- // Walk through the loaded drivers attempting to make a connection.
+ // Walk through the loaded registeredDrivers attempting to make a connection.
// Remember the first exception that gets raised so we can reraise it.
SQLException reason = null;
- for (int i = 0; i < drivers.size(); i++) {
- DriverInfo di = (DriverInfo)drivers.elementAt(i);
+ for(Driver aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
- if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
- println(" skipping: " + di);
- continue;
- }
- try {
- println(" trying " + di);
- Connection result = di.driver.connect(url, info);
- if (result != null) {
- // Success!
- println("getConnection returning " + di);
- return (result);
- }
- } catch (SQLException ex) {
- if (reason == null) {
- reason = ex;
+ if(isDriverAllowed(aDriver, callerCL)) {
+ try {
+ println(" trying " + aDriver.getClass().getName());
+ Connection con = aDriver.connect(url, info);
+ if (con != null) {
+ // Success!
+ println("getConnection returning " + aDriver.getClass().getName());
+ return (con);
+ }
+ } catch (SQLException ex) {
+ if (reason == null) {
+ reason = ex;
+ }
}
+
+ } else {
+ println(" skipping: " + aDriver.getClass().getName());
}
+
}
// if we got here nobody could connect.
@@ -640,45 +603,7 @@ public class DriverManager {
throw new SQLException("No suitable driver found for "+ url, "08001");
}
-
- // Class initialization.
- static void initialize() {
- if (initialized) {
- return;
- }
- initialized = true;
- loadInitialDrivers();
- println("JDBC DriverManager initialized");
- }
-
- /* Prevent the DriverManager class from being instantiated. */
- private DriverManager(){}
-
- /* write copy of the drivers vector */
- private static java.util.Vector writeDrivers = new java.util.Vector();
-
- /* write copy of the drivers vector */
- private static java.util.Vector readDrivers = new java.util.Vector();
-
- private static int loginTimeout = 0;
- private static java.io.PrintWriter logWriter = null;
- private static java.io.PrintStream logStream = null;
- private static boolean initialized = false;
-
- private static Object logSync = new Object();
-
/* Returns the caller's class loader, or null if none */
private static native ClassLoader getCallerClassLoader();
}
-
-// DriverInfo is a package-private support class.
-class DriverInfo {
- Driver driver;
- Class driverClass;
- String driverClassName;
-
- public String toString() {
- return ("driver[className=" + driverClassName + "," + driver + "]");
- }
-}
diff --git a/jdk/src/share/classes/java/util/Formatter.java b/jdk/src/share/classes/java/util/Formatter.java
index 797b9e2f8aa..6dcf8788052 100644
--- a/jdk/src/share/classes/java/util/Formatter.java
+++ b/jdk/src/share/classes/java/util/Formatter.java
@@ -1401,10 +1401,9 @@ import sun.misc.FormattedFloatingDecimal;
* The number of digits in the result for the fractional part of
* m or a is equal to the precision. If the precision is not
* specified then the default value is {@code 6}. If the precision is
- * less than the number of digits which would appear after the decimal
- * point in the string returned by {@link Float#toString(float)} or {@link
- * Double#toString(double)} respectively, then the value will be rounded
- * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ * less than the number of digits to the right of the decimal point then
+ * the value will be rounded using the
+ * {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
* algorithm}. Otherwise, zeros may be appended to reach the precision.
* For a canonical representation of the value, use {@link
* BigDecimal#toString()}.
@@ -1463,12 +1462,11 @@ import sun.misc.FormattedFloatingDecimal;
* more decimal digits representing the fractional part of m .
*
*
The number of digits in the result for the fractional part of
- * m or a is equal to the precision. If the precision is not
+ * m or a is equal to the precision. If the precision is not
* specified then the default value is {@code 6}. If the precision is
- * less than the number of digits which would appear after the decimal
- * point in the string returned by {@link Float#toString(float)} or {@link
- * Double#toString(double)} respectively, then the value will be rounded
- * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ * less than the number of digits to the right of the decimal point
+ * then the value will be rounded using the
+ * {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
* algorithm}. Otherwise, zeros may be appended to reach the precision.
* For a canonical representation of the value, use {@link
* BigDecimal#toString()}.
@@ -3585,7 +3583,7 @@ public final class Formatter implements Closeable, Flushable {
int scale = value.scale();
if (scale > prec) {
- // more "scale" digits than the requested "precision
+ // more "scale" digits than the requested "precision"
int compPrec = value.precision();
if (compPrec <= scale) {
// case of 0.xxxxxx
diff --git a/jdk/src/share/classes/java/util/JumboEnumSet.java b/jdk/src/share/classes/java/util/JumboEnumSet.java
index e3255963e56..398836a1c3b 100644
--- a/jdk/src/share/classes/java/util/JumboEnumSet.java
+++ b/jdk/src/share/classes/java/util/JumboEnumSet.java
@@ -34,6 +34,8 @@ package java.util;
* @serial exclude
*/
class JumboEnumSet> extends EnumSet {
+ private static final long serialVersionUID = 334349849919042784L;
+
/**
* Bit vector representation of this set. The ith bit of the jth
* element of this array represents the presence of universe[64*j +i]
@@ -138,8 +140,11 @@ class JumboEnumSet> extends EnumSet {
public void remove() {
if (lastReturned == 0)
throw new IllegalStateException();
- elements[lastReturnedIndex] -= lastReturned;
- size--;
+ final long oldElements = elements[lastReturnedIndex];
+ elements[lastReturnedIndex] &= ~lastReturned;
+ if (oldElements != elements[lastReturnedIndex]) {
+ size--;
+ }
lastReturned = 0;
}
}
diff --git a/jdk/src/share/classes/java/util/Locale.java b/jdk/src/share/classes/java/util/Locale.java
index efe200ed0db..63c8b03c4d3 100644
--- a/jdk/src/share/classes/java/util/Locale.java
+++ b/jdk/src/share/classes/java/util/Locale.java
@@ -1168,7 +1168,7 @@ public final class Locale implements Cloneable, Serializable {
boolean e = (_extensions.getID().length() != 0);
StringBuilder result = new StringBuilder(_baseLocale.getLanguage());
- if (r || (l && v)) {
+ if (r || (l && (v || s || e))) {
result.append('_')
.append(_baseLocale.getRegion()); // This may just append '_'
}
diff --git a/jdk/src/share/classes/java/util/RegularEnumSet.java b/jdk/src/share/classes/java/util/RegularEnumSet.java
index c4f6215461b..a549fae2de1 100644
--- a/jdk/src/share/classes/java/util/RegularEnumSet.java
+++ b/jdk/src/share/classes/java/util/RegularEnumSet.java
@@ -34,6 +34,7 @@ package java.util;
* @serial exclude
*/
class RegularEnumSet> extends EnumSet {
+ private static final long serialVersionUID = 3411599620347842686L;
/**
* Bit vector representation of this set. The 2^k bit indicates the
* presence of universe[k] in this set.
@@ -106,7 +107,7 @@ class RegularEnumSet> extends EnumSet {
public void remove() {
if (lastReturned == 0)
throw new IllegalStateException();
- elements -= lastReturned;
+ elements &= ~lastReturned;
lastReturned = 0;
}
}
diff --git a/jdk/src/share/classes/java/util/TreeMap.java b/jdk/src/share/classes/java/util/TreeMap.java
index e256240f306..d14ee9f4b66 100644
--- a/jdk/src/share/classes/java/util/TreeMap.java
+++ b/jdk/src/share/classes/java/util/TreeMap.java
@@ -528,11 +528,8 @@ public class TreeMap
public V put(K key, V value) {
Entry t = root;
if (t == null) {
- // TBD:
- // 5045147: (coll) Adding null to an empty TreeSet should
- // throw NullPointerException
- //
- // compare(key, key); // type check
+ compare(key, key); // type (and possibly null) check
+
root = new Entry<>(key, value, null);
size = 1;
modCount++;
diff --git a/jdk/src/share/classes/java/util/UUID.java b/jdk/src/share/classes/java/util/UUID.java
index c2d3a3184d6..348c8686e0a 100644
--- a/jdk/src/share/classes/java/util/UUID.java
+++ b/jdk/src/share/classes/java/util/UUID.java
@@ -26,8 +26,6 @@
package java.util;
import java.security.*;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
/**
* A class that represents an immutable universally unique identifier (UUID).
@@ -90,36 +88,6 @@ public final class UUID implements java.io.Serializable, Comparable {
*/
private final long leastSigBits;
- /*
- * The version number associated with this UUID. Computed on demand.
- */
- private transient int version = -1;
-
- /*
- * The variant number associated with this UUID. Computed on demand.
- */
- private transient int variant = -1;
-
- /*
- * The timestamp associated with this UUID. Computed on demand.
- */
- private transient volatile long timestamp = -1;
-
- /*
- * The clock sequence associated with this UUID. Computed on demand.
- */
- private transient int sequence = -1;
-
- /*
- * The node number associated with this UUID. Computed on demand.
- */
- private transient long node = -1;
-
- /*
- * The hashcode of this UUID. Computed on demand.
- */
- private transient int hashCode = -1;
-
/*
* The random number generator used by this class to create random
* based UUIDs.
@@ -134,7 +102,7 @@ public final class UUID implements java.io.Serializable, Comparable {
private UUID(byte[] data) {
long msb = 0;
long lsb = 0;
- assert data.length == 16;
+ assert data.length == 16 : "data must be 16 bytes in length";
for (int i=0; i<8; i++)
msb = (msb << 8) | (data[i] & 0xff);
for (int i=8; i<16; i++)
@@ -276,11 +244,8 @@ public final class UUID implements java.io.Serializable, Comparable {
* @return The version number of this {@code UUID}
*/
public int version() {
- if (version < 0) {
- // Version is bits masked by 0x000000000000F000 in MS long
- version = (int)((mostSigBits >> 12) & 0x0f);
- }
- return version;
+ // Version is bits masked by 0x000000000000F000 in MS long
+ return (int)((mostSigBits >> 12) & 0x0f);
}
/**
@@ -298,17 +263,13 @@ public final class UUID implements java.io.Serializable, Comparable {
* @return The variant number of this {@code UUID}
*/
public int variant() {
- if (variant < 0) {
- // This field is composed of a varying number of bits
- if ((leastSigBits >>> 63) == 0) {
- variant = 0;
- } else if ((leastSigBits >>> 62) == 2) {
- variant = 2;
- } else {
- variant = (int)(leastSigBits >>> 61);
- }
- }
- return variant;
+ // This field is composed of a varying number of bits.
+ // 0 - - Reserved for NCS backward compatibility
+ // 1 0 - The Leach-Salz variant (used by this class)
+ // 1 1 0 Reserved, Microsoft backward compatibility
+ // 1 1 1 Reserved for future definition.
+ return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62)))
+ & (leastSigBits >> 63));
}
/**
@@ -330,14 +291,10 @@ public final class UUID implements java.io.Serializable, Comparable {
if (version() != 1) {
throw new UnsupportedOperationException("Not a time-based UUID");
}
- long result = timestamp;
- if (result < 0) {
- result = (mostSigBits & 0x0000000000000FFFL) << 48;
- result |= ((mostSigBits >> 16) & 0xFFFFL) << 32;
- result |= mostSigBits >>> 32;
- timestamp = result;
- }
- return result;
+
+ return (mostSigBits & 0x0FFFL) << 48
+ | ((mostSigBits >> 16) & 0x0FFFFL) << 32
+ | mostSigBits >>> 32;
}
/**
@@ -360,10 +317,8 @@ public final class UUID implements java.io.Serializable, Comparable {
if (version() != 1) {
throw new UnsupportedOperationException("Not a time-based UUID");
}
- if (sequence < 0) {
- sequence = (int)((leastSigBits & 0x3FFF000000000000L) >>> 48);
- }
- return sequence;
+
+ return (int)((leastSigBits & 0x3FFF000000000000L) >>> 48);
}
/**
@@ -386,10 +341,8 @@ public final class UUID implements java.io.Serializable, Comparable {
if (version() != 1) {
throw new UnsupportedOperationException("Not a time-based UUID");
}
- if (node < 0) {
- node = leastSigBits & 0x0000FFFFFFFFFFFFL;
- }
- return node;
+
+ return leastSigBits & 0x0000FFFFFFFFFFFFL;
}
// Object Inherited Methods
@@ -438,13 +391,8 @@ public final class UUID implements java.io.Serializable, Comparable {
* @return A hash code value for this {@code UUID}
*/
public int hashCode() {
- if (hashCode == -1) {
- hashCode = (int)((mostSigBits >> 32) ^
- mostSigBits ^
- (leastSigBits >> 32) ^
- leastSigBits);
- }
- return hashCode;
+ long hilo = mostSigBits ^ leastSigBits;
+ return ((int)(hilo >> 32)) ^ (int) hilo;
}
/**
@@ -460,9 +408,7 @@ public final class UUID implements java.io.Serializable, Comparable {
* otherwise
*/
public boolean equals(Object obj) {
- if (!(obj instanceof UUID))
- return false;
- if (((UUID)obj).variant() != this.variant())
+ if ((null == obj) || (obj.getClass() != UUID.class))
return false;
UUID id = (UUID)obj;
return (mostSigBits == id.mostSigBits &&
@@ -494,23 +440,4 @@ public final class UUID implements java.io.Serializable, Comparable {
(this.leastSigBits > val.leastSigBits ? 1 :
0))));
}
-
- /**
- * Reconstitute the {@code UUID} instance from a stream (that is,
- * deserialize it). This is necessary to set the transient fields to their
- * correct uninitialized value so they will be recomputed on demand.
- */
- private void readObject(java.io.ObjectInputStream in)
- throws java.io.IOException, ClassNotFoundException {
-
- in.defaultReadObject();
-
- // Set "cached computation" fields to their initial values
- version = -1;
- variant = -1;
- timestamp = -1;
- sequence = -1;
- node = -1;
- hashCode = -1;
- }
}
diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java
index f1b11140291..37d218f6775 100644
--- a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java
+++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java
@@ -44,8 +44,8 @@ import java.util.concurrent.atomic.*;
* creation time, depending on which constructor is used.
*
* This class implements a concurrent variant of SkipLists providing
- * expected average log(n) time cost for the
+ * href="http://en.wikipedia.org/wiki/Skip_list" target="_top">SkipLists
+ * providing expected average log(n) time cost for the
* containsKey , get , put and
* remove operations and their variants. Insertion, removal,
* update, and access operations safely execute concurrently by
diff --git a/jdk/src/share/classes/java/util/concurrent/Exchanger.java b/jdk/src/share/classes/java/util/concurrent/Exchanger.java
index 8648278b755..e23f797c289 100644
--- a/jdk/src/share/classes/java/util/concurrent/Exchanger.java
+++ b/jdk/src/share/classes/java/util/concurrent/Exchanger.java
@@ -164,8 +164,8 @@ public class Exchanger {
* races between two threads or thread pre-emptions occurring
* between reading and CASing. Also, very transient peak
* contention can be much higher than the average sustainable
- * levels. The max limit is decreased on average 50% of the times
- * that a non-slot-zero wait elapses without being fulfilled.
+ * levels. An attempt to decrease the max limit is usually made
+ * when a non-slot-zero wait elapses without being fulfilled.
* Threads experiencing elapsed waits move closer to zero, so
* eventually find existing (or future) threads even if the table
* has been shrunk due to inactivity. The chosen mechanics and
diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java
index 22938fe4ba9..e298d151c1b 100644
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinPool.java
@@ -40,6 +40,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Random;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
@@ -51,6 +52,7 @@ import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.Condition;
/**
* An {@link ExecutorService} for running {@link ForkJoinTask}s.
@@ -158,239 +160,208 @@ public class ForkJoinPool extends AbstractExecutorService {
* set of worker threads: Submissions from non-FJ threads enter
* into a submission queue. Workers take these tasks and typically
* split them into subtasks that may be stolen by other workers.
- * The main work-stealing mechanics implemented in class
- * ForkJoinWorkerThread 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 worker queues, and
- * lastly to new submissions. These mechanics do not consider
- * 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.)
+ * 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 worker queues, and
+ * lastly to new submissions.
*
- * Beyond work-stealing support and essential bookkeeping, the
- * main responsibility of this framework is to take actions when
- * one worker is waiting to join a task stolen (or always held by)
- * another. Because we are multiplexing many tasks on to a pool
- * of workers, we can't 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. Given that the creation costs of most threads on most
- * systems mainly surrounds setting up runtime stacks, thread
- * creation and switching is usually not much more expensive than
- * stack creation and switching, and is more flexible). Instead we
+ * 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 a single 64bit volatile
+ * variable ("ctl"). This variable is read on the order of 10-100
+ * times as often as it is modified (always via CAS). (There is
+ * some additional control state, for example variable "shutdown"
+ * for which we can cope with uncoordinated updates.) This
+ * streamlines synchronization and control at the expense of messy
+ * constructions needed to repack status bits upon updates.
+ * Updates tend not to contend with each other except during
+ * bursts while submitted tasks begin or end. In some cases when
+ * they do contend, threads can instead do something else
+ * (usually, scan for tasks) until contention subsides.
+ *
+ * To enable 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.
+ *
+ * Recording Workers. Workers are recorded in the "workers" array
+ * that is created upon pool construction and expanded if (rarely)
+ * necessary. This is an array as opposed to some other data
+ * structure to support index-based random steals by workers.
+ * Updates to the array recording new workers and unrecording
+ * terminated ones are protected from each other by a seqLock
+ * (scanGuard) but the array is otherwise concurrently readable,
+ * and accessed directly by workers. To simplify index-based
+ * operations, the array size is always a power of two, and all
+ * readers must tolerate null slots. To avoid flailing during
+ * start-up, the array is presized to hold twice #parallelism
+ * workers (which is unlikely to need further resizing during
+ * execution). But to avoid dealing with so many null slots,
+ * variable scanGuard includes a mask for the nearest power of two
+ * that contains all current workers. 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 accesses to workers are
+ * via indices into the workers array (which is one source of some
+ * of the messy code constructions here). In essence, the workers
+ * array serves as a weak reference mechanism. Thus for example
+ * the wait queue field of ctl stores worker indices, not worker
+ * references. Access to the workers 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 workers array, as well as queue arrays, check
+ * that the array 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.
+ *
+ * Wait 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. 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 to both wake up waiters (by advancing their
+ * count) and avoid ABA effects. Successors are held in worker
+ * field "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 both before (in scan()) and after
+ * (in tryAwaitWork()) a newly waiting worker is added to the wait
+ * queue. During a rescan, the worker might release some other
+ * queued worker rather than itself, which has the same net
+ * effect. Because enqueued workers may actually be rescanning
+ * rather than waiting, we set and clear the "parked" field of
+ * ForkJoinWorkerThread to reduce unnecessary calls to unpark.
+ * (Use of the parked field requires a secondary recheck to avoid
+ * missed signals.)
+ *
+ * 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 previously had two or fewer tasks, they
+ * signal waiting workers (or trigger creation of new ones if
+ * fewer than the given parallelism level -- see signalWork).
+ * These primary signals are buttressed by signals during rescans
+ * as well as those performed when a worker steals a task and
+ * notices that there are more tasks too; together these cover the
+ * signals needed in cases when more than two tasks are pushed
+ * but untaken.
+ *
+ * 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
+ * SHRINK_RATE nanosecs. This will slowly propagate, eventually
+ * terminating all workers after long periods of non-use.
+ *
+ * Submissions. External submissions are maintained in an
+ * array-based queue that is structured identically to
+ * ForkJoinWorkerThread queues except for the use of
+ * submissionLock in method addSubmission. Unlike the case for
+ * worker queues, multiple external threads can add new
+ * submissions, so adding requires a lock.
+ *
+ * Compensation. Beyond work-stealing support and lifecycle
+ * control, the main responsibility of this framework is to take
+ * actions when one worker is waiting to join a task stolen (or
+ * always held by) another. Because we are multiplexing many
+ * tasks on to a pool of workers, we can't 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:
*
* Helping: Arranging for the joiner to execute some task that it
* would be running if the steal had not occurred. Method
- * ForkJoinWorkerThread.helpJoinTask tracks joining->stealing
+ * ForkJoinWorkerThread.joinTask tracks joining->stealing
* links to try to find such a task.
*
* Compensating: Unless there are already enough live threads,
- * method helpMaintainParallelism() may create or
- * re-activate a spare thread to compensate for blocked
- * joiners until they unblock.
- *
- * It is impossible to keep exactly the target (parallelism)
- * number of threads running at any given time. Determining
- * existence of conservatively safe helping targets, the
- * availability of already-created spares, and the apparent need
- * to create new spares are all racy and require heuristic
- * guidance, so we rely on multiple retries of each. Compensation
- * occurs in slow-motion. It is triggered only upon timeouts of
- * Object.wait used for joins. This reduces poor decisions that
- * would otherwise be made when threads are waiting for others
- * that are stalled because of unrelated activities such as
- * garbage collection.
+ * method tryPreBlock() may create or re-activate a spare
+ * thread to compensate for blocked joiners until they
+ * unblock.
*
* The ManagedBlocker extension API can't use helping so relies
* only on compensation in method awaitBlocker.
*
- * The main throughput advantages of work-stealing stem from
- * decentralized control -- workers mostly steal tasks from each
- * other. We do not want to negate this by creating bottlenecks
- * implementing other management responsibilities. So we use a
- * collection of techniques that avoid, reduce, or cope well with
- * contention. These entail several instances of bit-packing into
- * CASable fields to maintain only the minimally required
- * atomicity. To enable such packing, we restrict maximum
- * parallelism to (1<<15)-1 (enabling twice this (to accommodate
- * unbalanced increments and decrements) to fit into a 16 bit
- * field, which is far in excess of normal operating range. Even
- * though updates to some of these bookkeeping fields do sometimes
- * contend with each other, they don't normally cache-contend with
- * updates to others enough to warrant memory padding or
- * isolation. So they are all held as fields of ForkJoinPool
- * objects. The main capabilities are as follows:
+ * 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 and require heuristic
+ * guidance, so we rely on multiple retries of each. Currently,
+ * in keeping with on-demand signalling policy, we compensate only
+ * if blocking would leave less than one active (non-waiting,
+ * non-blocked) worker. Additionally, to avoid some false alarms
+ * due to GC, lagging counters, system activity, etc, compensated
+ * blocking for joins is only attempted after rechecks stabilize
+ * (retries are interspersed with Thread.yield, for good
+ * citizenship). The variable blockedCount, incremented before
+ * blocking and decremented after, is sometimes needed to
+ * distinguish cases of waiting for work vs blocking on joins or
+ * other managed sync. Both cases are equivalent for most pool
+ * control, so we can update non-atomically. (Additionally,
+ * contention on blockedCount alleviates some contention on ctl).
*
- * 1. Creating and removing workers. Workers are recorded in the
- * "workers" array. This is an array as opposed to some other data
- * structure to support index-based random steals by workers.
- * Updates to the array recording new workers and unrecording
- * terminated ones are protected from each other by a lock
- * (workerLock) but the array is otherwise concurrently readable,
- * and accessed directly by workers. To simplify index-based
- * operations, the array size is always a power of two, and all
- * readers must tolerate null slots. Currently, 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.
+ * Shutdown and Termination. A call to shutdownNow atomically sets
+ * the ctl stop bit and then (non-atomically) sets each workers
+ * "terminate" 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 quiesence (i.e., that
+ * there is no more work) which is reflected in active counts so
+ * long as there are no current blockers, as well as possible
+ * re-evaluations during independent changes in blocking or
+ * quiescing workers.
*
- * To ensure that we do not hold on to worker references that
- * would prevent GC, ALL accesses to workers are via indices into
- * the workers array (which is one source of some of the unusual
- * code constructions here). In essence, the workers array serves
- * as a WeakReference mechanism. Thus for example the event queue
- * stores worker indices, not worker references. Access to the
- * workers in associated methods (for example releaseEventWaiters)
- * 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 shutdown, in which case
- * it is OK to give up. On termination, we just clobber these
- * data structures without trying to use them.
- *
- * 2. Bookkeeping for dynamically adding and removing workers. We
- * aim to approximately maintain the given level of parallelism.
- * When some workers are known to be blocked (on joins or via
- * ManagedBlocker), we may create or resume others to take their
- * place until they unblock (see below). Implementing this
- * requires counts of the number of "running" threads (i.e., those
- * that are neither blocked nor artificially suspended) as well as
- * the total number. These two values are packed into one field,
- * "workerCounts" because we need accurate snapshots when deciding
- * to create, resume or suspend. Note however that the
- * correspondence of these counts to reality is not guaranteed. In
- * particular updates for unblocked threads may lag until they
- * actually wake up.
- *
- * 3. Maintaining global run state. The run state of the pool
- * consists of a runLevel (SHUTDOWN, TERMINATING, etc) similar to
- * those in other Executor implementations, as well as a count of
- * "active" workers -- those that are, or soon will be, or
- * recently were executing tasks. The runLevel and active count
- * are packed together in order to correctly trigger shutdown and
- * termination. Without care, active counts can be subject to very
- * high contention. We substantially reduce this contention by
- * relaxing update rules. A worker must claim active status
- * prospectively, by activating if it sees that a submitted or
- * stealable task exists (it may find after activating that the
- * task no longer exists). It stays active while processing this
- * task (if it exists) and any other local subtasks it produces,
- * until it cannot find any other tasks. It then tries
- * inactivating (see method preStep), but upon update contention
- * instead scans for more tasks, later retrying inactivation if it
- * doesn't find any.
- *
- * 4. Managing idle workers waiting for tasks. We cannot let
- * workers spin indefinitely scanning for tasks when none are
- * available. On the other hand, we must quickly prod them into
- * action when new tasks are submitted or generated. We
- * park/unpark these idle workers using an event-count scheme.
- * Field eventCount is incremented upon events that may enable
- * workers that previously could not find a task to now find one:
- * Submission of a new task to the pool, or another worker pushing
- * a task onto a previously empty queue. (We also use this
- * mechanism for configuration and termination actions that
- * require wakeups of idle workers). Each worker maintains its
- * last known event count, and blocks when a scan for work did not
- * find a task AND its lastEventCount matches the current
- * eventCount. Waiting idle workers are recorded in a variant of
- * Treiber stack headed by field eventWaiters which, when nonzero,
- * encodes the thread index and count awaited for by the worker
- * thread most recently calling eventSync. This thread in turn has
- * a record (field nextEventWaiter) for the next waiting worker.
- * In addition to allowing simpler decisions about need for
- * wakeup, the event count bits in eventWaiters serve the role of
- * tags to avoid ABA errors in Treiber stacks. Upon any wakeup,
- * released threads also try to release at most two others. The
- * net effect is a tree-like diffusion of signals, where released
- * threads (and possibly others) help with unparks. To further
- * reduce contention effects a bit, failed CASes to increment
- * field eventCount are tolerated without retries in signalWork.
- * Conceptually they are merged into the same event, which is OK
- * when their only purpose is to enable workers to scan for work.
- *
- * 5. Managing suspension of extra workers. When a worker notices
- * (usually upon timeout of a wait()) that there are too few
- * running threads, we may create a new thread to maintain
- * parallelism level, or at least avoid starvation. Usually, extra
- * threads are needed for only very short periods, yet join
- * dependencies are such that we sometimes need them in
- * bursts. Rather than create new threads each time this happens,
- * we suspend no-longer-needed extra ones as "spares". For most
- * purposes, we don't distinguish "extra" spare threads from
- * normal "core" threads: On each call to preStep (the only point
- * at which we can do this) a worker checks to see if there are
- * now too many running workers, and if so, suspends itself.
- * Method helpMaintainParallelism looks for suspended threads to
- * resume before considering creating a new replacement. The
- * spares themselves are encoded on another variant of a Treiber
- * Stack, headed at field "spareWaiters". Note that the use of
- * spares is intrinsically racy. One thread may become a spare at
- * about the same time as another is needlessly being created. We
- * counteract this and related slop in part by requiring resumed
- * spares to immediately recheck (in preStep) to see whether they
- * should re-suspend.
- *
- * 6. Killing off unneeded workers. A timeout mechanism is used to
- * shed unused workers: The oldest (first) event queue waiter uses
- * a timed rather than hard wait. When this wait times out without
- * a normal wakeup, it tries to shutdown any one (for convenience
- * the newest) other spare or event waiter via
- * tryShutdownUnusedWorker. This eventually reduces the number of
- * worker threads to a minimum of one after a long enough period
- * without use.
- *
- * 7. Deciding when to create new workers. The main dynamic
- * control in this class is deciding when to create extra threads
- * in method helpMaintainParallelism. We would like to keep
- * exactly #parallelism threads running, which is an impossible
- * task. We always need to create one when the number of running
- * threads would become zero and all workers are busy. Beyond
- * this, we must rely on heuristics that work well in the
- * presence of transient phenomena such as GC stalls, dynamic
- * compilation, and wake-up lags. These transients are extremely
- * common -- we are normally trying to fully saturate the CPUs on
- * a machine, so almost any activity other than running tasks
- * impedes accuracy. Our main defense is to allow parallelism to
- * lapse for a while during joins, and use a timeout to see if,
- * after the resulting settling, there is still a need for
- * additional workers. This also better copes with the fact that
- * some of the methods in this class tend to never become compiled
- * (but are interpreted), so some components of the entire set of
- * controls might execute 100 times faster than others. And
- * similarly for cases where the apparent lack of work is just due
- * to GC stalls and other transient system activity.
- *
- * Beware that there is a lot of representation-level coupling
+ * Style notes: There is a lot of representation-level coupling
* among classes ForkJoinPool, ForkJoinWorkerThread, and
- * ForkJoinTask. For example, direct access to "workers" array by
+ * ForkJoinTask. Most fields of ForkJoinWorkerThread maintain
+ * data structures managed by ForkJoinPool, so are directly
+ * accessed. Conversely we allow access to "workers" array by
* workers, and direct access to ForkJoinTask.status by both
* ForkJoinPool and ForkJoinWorkerThread. There is little point
* trying to reduce this, since any associated future changes in
* representations will need to be accompanied by algorithmic
- * changes anyway.
+ * changes anyway. All together, these low-level implementation
+ * choices produce as much as a factor of 4 performance
+ * improvement compared to naive implementations, and enable the
+ * processing of billions of tasks per second, at the expense of
+ * some ugliness.
*
- * Style notes: 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). Also 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 that
- * help some methods perform reasonably even when interpreted (not
- * compiled), at the expense of some messy constructions that
- * reduce byte code counts.
+ * 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 that help some methods perform reasonably even
+ * when interpreted (not compiled).
*
- * The order of declarations in this file is: (1) statics (2)
- * fields (along with constants used when unpacking some of them)
- * (3) internal control methods (4) callbacks and other support
- * for ForkJoinTask and ForkJoinWorkerThread classes, (5) exported
- * methods (plus a few little helpers).
+ * The order of declarations in this file is: (1) declarations of
+ * statics (2) fields (along with constants used when unpacking
+ * some of them), listed in an order that tends to reduce
+ * contention among them a bit under most JVMs. (3) internal
+ * control methods (4) callbacks and other support for
+ * ForkJoinTask and ForkJoinWorkerThread classes, (5) exported
+ * methods (plus a few little helpers). (6) static block
+ * initializing all statics in a minimally dependent order.
*/
/**
@@ -425,15 +396,13 @@ public class ForkJoinPool extends AbstractExecutorService {
* overridden in ForkJoinPool constructors.
*/
public static final ForkJoinWorkerThreadFactory
- defaultForkJoinWorkerThreadFactory =
- new DefaultForkJoinWorkerThreadFactory();
+ defaultForkJoinWorkerThreadFactory;
/**
* Permission required for callers of methods that may start or
* kill threads.
*/
- private static final RuntimePermission modifyThreadPermission =
- new RuntimePermission("modifyThread");
+ private static final RuntimePermission modifyThreadPermission;
/**
* If there is a security manager, makes sure caller has
@@ -448,69 +417,76 @@ public class ForkJoinPool extends AbstractExecutorService {
/**
* Generator for assigning sequence numbers as pool names.
*/
- private static final AtomicInteger poolNumberGenerator =
- new AtomicInteger();
+ private static final AtomicInteger poolNumberGenerator;
/**
- * The time to block in a join (see awaitJoin) before checking if
- * a new worker should be (re)started to maintain parallelism
- * level. The value should be short enough to maintain global
- * responsiveness and progress but long enough to avoid
- * counterproductive firings during GC stalls or unrelated system
- * activity, and to not bog down systems with continual re-firings
- * on GCs or legitimately long waits.
+ * Generator for initial random seeds for worker victim
+ * selection. This is used only to create initial seeds. Random
+ * steals use a cheaper xorshift generator per steal attempt. We
+ * don't expect much contention on seedGenerator, so just use a
+ * plain Random.
*/
- private static final long JOIN_TIMEOUT_MILLIS = 250L; // 4 per second
+ static final Random workerSeedGenerator;
/**
- * The wakeup interval (in nanoseconds) for the oldest worker
- * waiting for an event to invoke tryShutdownUnusedWorker to
- * shrink the number of workers. The exact value does not matter
- * too much. It must be short enough to release resources during
- * sustained periods of idleness, but not so short that threads
- * are continually re-created.
+ * Array holding all worker threads in the pool. Initialized upon
+ * construction. Array size must be a power of two. Updates and
+ * replacements are protected by scanGuard, but the array is
+ * always kept in a consistent enough state to be randomly
+ * accessed without locking by workers performing work-stealing,
+ * as well as other traversal-based methods in this class, so long
+ * as reads memory-acquire by first reading ctl. All readers must
+ * tolerate that some array slots may be null.
*/
- private static final long SHRINK_RATE_NANOS =
- 30L * 1000L * 1000L * 1000L; // 2 per minute
+ ForkJoinWorkerThread[] workers;
/**
- * Absolute bound for parallelism level. Twice this number plus
- * one (i.e., 0xfff) must fit into a 16bit field to enable
- * word-packing for some counts and indices.
+ * Initial size for submission queue array. Must be a power of
+ * two. In many applications, these always stay small so we use a
+ * small initial cap.
*/
- private static final int MAX_WORKERS = 0x7fff;
+ private static final int INITIAL_QUEUE_CAPACITY = 8;
/**
- * Array holding all worker threads in the pool. Array size must
- * be a power of two. Updates and replacements are protected by
- * workerLock, but the array is always kept in a consistent enough
- * state to be randomly accessed without locking by workers
- * performing work-stealing, as well as other traversal-based
- * methods in this class. All readers must tolerate that some
- * array slots may be null.
+ * Maximum size for submission queue array. Must be a power of two
+ * less than or equal to 1 << (31 - width of array entry) to
+ * ensure lack of index wraparound, but is capped at a lower
+ * value to help users trap runaway computations.
*/
- volatile ForkJoinWorkerThread[] workers;
+ private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 24; // 16M
/**
- * Queue for external submissions.
+ * Array serving as submission queue. Initialized upon construction.
*/
- private final LinkedTransferQueue> submissionQueue;
+ private ForkJoinTask>[] submissionQueue;
/**
- * Lock protecting updates to workers array.
+ * Lock protecting submissions array for addSubmission
*/
- private final ReentrantLock workerLock;
+ private final ReentrantLock submissionLock;
/**
- * Latch released upon termination.
+ * Condition for awaitTermination, using submissionLock for
+ * convenience.
*/
- private final Phaser termination;
+ private final Condition termination;
/**
* Creation factory for worker threads.
*/
private final ForkJoinWorkerThreadFactory factory;
+ /**
+ * The uncaught exception handler used when any worker abruptly
+ * terminates.
+ */
+ final Thread.UncaughtExceptionHandler ueh;
+
+ /**
+ * Prefix for assigning names to worker threads
+ */
+ private final String workerNamePrefix;
+
/**
* Sum of per-thread steal counts, updated only when threads are
* idle or terminating.
@@ -518,82 +494,87 @@ public class ForkJoinPool extends AbstractExecutorService {
private volatile long stealCount;
/**
- * Encoded record of top of Treiber stack of threads waiting for
- * events. The top 32 bits contain the count being waited for. The
- * bottom 16 bits contains one plus the pool index of waiting
- * worker thread. (Bits 16-31 are unused.)
- */
- private volatile long eventWaiters;
-
- private static final int EVENT_COUNT_SHIFT = 32;
- private static final int WAITER_ID_MASK = (1 << 16) - 1;
-
- /**
- * A counter for events that may wake up worker threads:
- * - Submission of a new task to the pool
- * - A worker pushing a task on an empty queue
- * - termination
- */
- private volatile int eventCount;
-
- /**
- * Encoded record of top of Treiber stack of spare threads waiting
- * for resumption. The top 16 bits contain an arbitrary count to
- * avoid ABA effects. The bottom 16bits contains one plus the pool
- * index of waiting worker thread.
- */
- private volatile int spareWaiters;
-
- private static final int SPARE_COUNT_SHIFT = 16;
- private static final int SPARE_ID_MASK = (1 << 16) - 1;
-
- /**
- * Lifecycle control. The low word contains the number of workers
- * that are (probably) executing tasks. This value is atomically
- * incremented before a worker gets a task to run, and decremented
- * when a worker has no tasks and cannot find any. Bits 16-18
- * contain runLevel value. When all are zero, the pool is
- * running. Level transitions are monotonic (running -> shutdown
- * -> terminating -> terminated) so each transition adds a bit.
- * These are bundled together to ensure consistent read for
- * termination checks (i.e., that runLevel is at least SHUTDOWN
- * and active threads is zero).
+ * Main pool control -- a long packed with:
+ * AC: Number of active running workers minus target parallelism (16 bits)
+ * TC: Number of total workers minus target parallelism (16bits)
+ * 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 waiting threads (16 bits)
*
- * Notes: Most direct CASes are dependent on these bitfield
- * positions. Also, this field is non-private to enable direct
- * performance-sensitive CASes in ForkJoinWorkerThread.
+ * 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, when id is
+ * negative, there is at least one waiting worker, 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.
*/
- volatile int runState;
+ volatile long ctl;
- // Note: The order among run level values matters.
- private static final int RUNLEVEL_SHIFT = 16;
- private static final int SHUTDOWN = 1 << RUNLEVEL_SHIFT;
- private static final int TERMINATING = 1 << (RUNLEVEL_SHIFT + 1);
- private static final int TERMINATED = 1 << (RUNLEVEL_SHIFT + 2);
- private static final int ACTIVE_COUNT_MASK = (1 << RUNLEVEL_SHIFT) - 1;
+ // bit positions/shifts for fields
+ private static final int AC_SHIFT = 48;
+ private static final int TC_SHIFT = 32;
+ private static final int ST_SHIFT = 31;
+ private static final int EC_SHIFT = 16;
- /**
- * Holds number of total (i.e., created and not yet terminated)
- * and running (i.e., not blocked on joins or other managed sync)
- * threads, packed together to ensure consistent snapshot when
- * making decisions about creating and suspending spare
- * threads. Updated only by CAS. Note that adding a new worker
- * requires incrementing both counts, since workers start off in
- * running state.
- */
- private volatile int workerCounts;
+ // bounds
+ private static final int MAX_ID = 0x7fff; // max poolIndex
+ private static final int SMASK = 0xffff; // mask short bits
+ private static final int SHORT_SIGN = 1 << 15;
+ private static final int INT_SIGN = 1 << 31;
- private static final int TOTAL_COUNT_SHIFT = 16;
- private static final int RUNNING_COUNT_MASK = (1 << TOTAL_COUNT_SHIFT) - 1;
- private static final int ONE_RUNNING = 1;
- private static final int ONE_TOTAL = 1 << TOTAL_COUNT_SHIFT;
+ // 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 EC_UNIT = 1 << EC_SHIFT;
/**
* The target parallelism level.
- * Accessed directly by ForkJoinWorkerThreads.
*/
final int parallelism;
+ /**
+ * Index (mod submission queue length) of next element to take
+ * from submission queue. Usage is identical to that for
+ * per-worker queues -- see ForkJoinWorkerThread internal
+ * documentation.
+ */
+ volatile int queueBase;
+
+ /**
+ * Index (mod submission queue length) of next element to add
+ * in submission queue. Usage is identical to that for
+ * per-worker queues -- see ForkJoinWorkerThread internal
+ * documentation.
+ */
+ int queueTop;
+
+ /**
+ * True when shutdown() has been called.
+ */
+ volatile boolean shutdown;
+
/**
* True if use local fifo, not default lifo, for local polling
* Read by, and replicated by ForkJoinWorkerThreads
@@ -601,139 +582,615 @@ public class ForkJoinPool extends AbstractExecutorService {
final boolean locallyFifo;
/**
- * The uncaught exception handler used when any worker abruptly
- * terminates.
+ * The number of threads in ForkJoinWorkerThreads.helpQuiescePool.
+ * When non-zero, suppresses automatic shutdown when active
+ * counts become zero.
*/
- private final Thread.UncaughtExceptionHandler ueh;
+ volatile int quiescerCount;
/**
- * Pool number, just for assigning useful names to worker threads
+ * The number of threads blocked in join.
*/
- private final int poolNumber;
-
- // Utilities for CASing fields. Note that most of these
- // are usually manually inlined by callers
+ volatile int blockedCount;
/**
- * Increments running count part of workerCounts.
+ * Counter for worker Thread names (unrelated to their poolIndex)
*/
- final void incrementRunningCount() {
- int c;
- do {} while (!UNSAFE.compareAndSwapInt(this, workerCountsOffset,
- c = workerCounts,
- c + ONE_RUNNING));
- }
+ private volatile int nextWorkerNumber;
/**
- * Tries to increment running count part of workerCounts.
+ * The index for the next created worker. Accessed under scanGuard.
*/
- final boolean tryIncrementRunningCount() {
- int c;
- return UNSAFE.compareAndSwapInt(this, workerCountsOffset,
- c = workerCounts,
- c + ONE_RUNNING);
- }
+ private int nextWorkerIndex;
/**
- * Tries to decrement running count unless already zero.
+ * SeqLock and index masking for updates to workers array. Locked
+ * when SG_UNIT is set. Unlocking clears bit by adding
+ * SG_UNIT. Staleness of read-only operations can be checked by
+ * comparing scanGuard to value before the reads. The low 16 bits
+ * (i.e, anding with SMASK) hold (the smallest power of two
+ * covering all worker indices, minus one, and is used to avoid
+ * dealing with large numbers of null slots when the workers array
+ * is overallocated.
*/
- final boolean tryDecrementRunningCount() {
- int wc = workerCounts;
- if ((wc & RUNNING_COUNT_MASK) == 0)
- return false;
- return UNSAFE.compareAndSwapInt(this, workerCountsOffset,
- wc, wc - ONE_RUNNING);
- }
+ volatile int scanGuard;
+
+ private static final int SG_UNIT = 1 << 16;
/**
- * Forces decrement of encoded workerCounts, awaiting nonzero if
- * (rarely) necessary when other count updates lag.
+ * The wakeup interval (in nanoseconds) for a worker waiting for a
+ * task when the pool is quiescent to instead try to shrink the
+ * number of workers. The exact value does not matter too
+ * much. It must be short enough to release resources during
+ * sustained periods of idleness, but not so short that threads
+ * are continually re-created.
+ */
+ private static final long SHRINK_RATE =
+ 4L * 1000L * 1000L * 1000L; // 4 seconds
+
+ /**
+ * Top-level loop for worker threads: On each step: if the
+ * previous step swept through all queues and found no tasks, or
+ * there are excess threads, then possibly blocks. Otherwise,
+ * scans for and, if found, executes a task. Returns when pool
+ * and/or worker terminate.
*
- * @param dr -- either zero or ONE_RUNNING
- * @param dt -- either zero or ONE_TOTAL
+ * @param w the worker
*/
- private void decrementWorkerCounts(int dr, int dt) {
- for (;;) {
- int wc = workerCounts;
- if ((wc & RUNNING_COUNT_MASK) - dr < 0 ||
- (wc >>> TOTAL_COUNT_SHIFT) - dt < 0) {
- if ((runState & TERMINATED) != 0)
- return; // lagging termination on a backout
- Thread.yield();
+ final void work(ForkJoinWorkerThread w) {
+ boolean swept = false; // true on empty scans
+ long c;
+ while (!w.terminate && (int)(c = ctl) >= 0) {
+ int a; // active count
+ if (!swept && (a = (int)(c >> AC_SHIFT)) <= 0)
+ swept = scan(w, a);
+ else if (tryAwaitWork(w, c))
+ swept = false;
+ }
+ }
+
+ // Signalling
+
+ /**
+ * Wakes up or creates a worker.
+ */
+ final void signalWork() {
+ /*
+ * The while condition is true if: (there is are too few total
+ * workers OR there is at least one waiter) AND (there are too
+ * few active workers OR the pool is terminating). The value
+ * of e distinguishes the remaining cases: zero (no waiters)
+ * for create, negative if terminating (in which case do
+ * nothing), else release a waiter. The secondary checks for
+ * release (non-null array etc) can fail if the pool begins
+ * terminating after the test, and don't impose any added cost
+ * because JVMs must perform null and bounds checks anyway.
+ */
+ long c; int e, u;
+ while ((((e = (int)(c = ctl)) | (u = (int)(c >>> 32))) &
+ (INT_SIGN|SHORT_SIGN)) == (INT_SIGN|SHORT_SIGN) && e >= 0) {
+ if (e > 0) { // release a waiting worker
+ int i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws;
+ if ((ws = workers) == null ||
+ (i = ~e & SMASK) >= ws.length ||
+ (w = ws[i]) == null)
+ break;
+ long nc = (((long)(w.nextWait & E_MASK)) |
+ ((long)(u + UAC_UNIT) << 32));
+ if (w.eventCount == e &&
+ UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
+ w.eventCount = (e + EC_UNIT) & E_MASK;
+ if (w.parked)
+ UNSAFE.unpark(w);
+ break;
+ }
+ }
+ else if (UNSAFE.compareAndSwapLong
+ (this, ctlOffset, c,
+ (long)(((u + UTC_UNIT) & UTC_MASK) |
+ ((u + UAC_UNIT) & UAC_MASK)) << 32)) {
+ addWorker();
+ break;
}
- if (UNSAFE.compareAndSwapInt(this, workerCountsOffset,
- wc, wc - (dr + dt)))
- return;
}
}
/**
- * Tries decrementing active count; fails on contention.
- * Called when workers cannot find tasks to run.
+ * Variant of signalWork to help release waiters on rescans.
+ * Tries once to release a waiter if active count < 0.
+ *
+ * @return false if failed due to contention, else true
*/
- final boolean tryDecrementActiveCount() {
- int c;
- return UNSAFE.compareAndSwapInt(this, runStateOffset,
- c = runState, c - 1);
- }
-
- /**
- * Advances to at least the given level. Returns true if not
- * already in at least the given level.
- */
- private boolean advanceRunLevel(int level) {
- for (;;) {
- int s = runState;
- if ((s & level) != 0)
+ private boolean tryReleaseWaiter() {
+ long c; int e, i; ForkJoinWorkerThread w; ForkJoinWorkerThread[] ws;
+ if ((e = (int)(c = ctl)) > 0 &&
+ (int)(c >> AC_SHIFT) < 0 &&
+ (ws = workers) != null &&
+ (i = ~e & SMASK) < ws.length &&
+ (w = ws[i]) != null) {
+ long nc = ((long)(w.nextWait & E_MASK) |
+ ((c + AC_UNIT) & (AC_MASK|TC_MASK)));
+ if (w.eventCount != e ||
+ !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc))
return false;
- if (UNSAFE.compareAndSwapInt(this, runStateOffset, s, s | level))
- return true;
+ w.eventCount = (e + EC_UNIT) & E_MASK;
+ if (w.parked)
+ UNSAFE.unpark(w);
}
+ return true;
}
- // workers array maintenance
+ // Scanning for tasks
/**
- * Records and returns a workers array index for new worker.
+ * Scans for and, if found, executes one task. Scans start at a
+ * random index of workers array, and randomly select the first
+ * (2*#workers)-1 probes, and then, if all empty, resort to 2
+ * circular sweeps, which is necessary to check quiescence. and
+ * taking a submission only if no stealable tasks were found. The
+ * steal code inside the loop is a specialized form of
+ * ForkJoinWorkerThread.deqTask, followed bookkeeping to support
+ * helpJoinTask and signal propagation. The code for submission
+ * queues is almost identical. On each steal, the worker completes
+ * not only the task, but also all local tasks that this task may
+ * have generated. On detecting staleness or contention when
+ * trying to take a task, this method returns without finishing
+ * sweep, which allows global state rechecks before retry.
+ *
+ * @param w the worker
+ * @param a the number of active workers
+ * @return true if swept all queues without finding a task
*/
- private int recordWorker(ForkJoinWorkerThread w) {
- // Try using slot totalCount-1. If not available, scan and/or resize
- int k = (workerCounts >>> TOTAL_COUNT_SHIFT) - 1;
- final ReentrantLock lock = this.workerLock;
- lock.lock();
- try {
- ForkJoinWorkerThread[] ws = workers;
- int n = ws.length;
- if (k < 0 || k >= n || ws[k] != null) {
- for (k = 0; k < n && ws[k] != null; ++k)
- ;
- if (k == n)
- ws = workers = Arrays.copyOf(ws, n << 1);
+ private boolean scan(ForkJoinWorkerThread w, int a) {
+ int g = scanGuard; // mask 0 avoids useless scans if only one active
+ int m = (parallelism == 1 - a && blockedCount == 0) ? 0 : g & SMASK;
+ ForkJoinWorkerThread[] ws = workers;
+ if (ws == null || ws.length <= m) // staleness check
+ return false;
+ for (int r = w.seed, k = r, j = -(m + m); j <= m + m; ++j) {
+ ForkJoinTask> t; ForkJoinTask>[] q; int b, i;
+ ForkJoinWorkerThread v = ws[k & m];
+ if (v != null && (b = v.queueBase) != v.queueTop &&
+ (q = v.queue) != null && (i = (q.length - 1) & b) >= 0) {
+ long u = (i << ASHIFT) + ABASE;
+ if ((t = q[i]) != null && v.queueBase == b &&
+ UNSAFE.compareAndSwapObject(q, u, t, null)) {
+ int d = (v.queueBase = b + 1) - v.queueTop;
+ v.stealHint = w.poolIndex;
+ if (d != 0)
+ signalWork(); // propagate if nonempty
+ w.execTask(t);
+ }
+ r ^= r << 13; r ^= r >>> 17; w.seed = r ^ (r << 5);
+ return false; // store next seed
}
- ws[k] = w;
- int c = eventCount; // advance event count to ensure visibility
- UNSAFE.compareAndSwapInt(this, eventCountOffset, c, c+1);
- } finally {
- lock.unlock();
+ else if (j < 0) { // xorshift
+ r ^= r << 13; r ^= r >>> 17; k = r ^= r << 5;
+ }
+ else
+ ++k;
+ }
+ if (scanGuard != g) // staleness check
+ return false;
+ else { // try to take submission
+ ForkJoinTask> t; ForkJoinTask>[] q; int b, i;
+ if ((b = queueBase) != queueTop &&
+ (q = submissionQueue) != null &&
+ (i = (q.length - 1) & b) >= 0) {
+ long u = (i << ASHIFT) + ABASE;
+ if ((t = q[i]) != null && queueBase == b &&
+ UNSAFE.compareAndSwapObject(q, u, t, null)) {
+ queueBase = b + 1;
+ w.execTask(t);
+ }
+ return false;
+ }
+ return true; // all queues empty
}
- return k;
}
/**
- * Nulls out record of worker in workers array.
+ * Tries to enqueue worker w in wait queue and await change in
+ * worker's eventCount. If the pool is quiescent, possibly
+ * terminates worker upon exit. Otherwise, before blocking,
+ * rescans queues to avoid missed signals. Upon finding work,
+ * releases at least one worker (which may be the current
+ * worker). Rescans restart upon detected staleness or failure to
+ * release due to contention. Note the unusual conventions about
+ * Thread.interrupt here and elsewhere: Because interrupts are
+ * used solely to alert threads to check termination, which is
+ * checked here anyway, 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.
+ *
+ * @param w the calling worker
+ * @param c the ctl value on entry
+ * @return true if waited or another thread was released upon enq
*/
- private void forgetWorker(ForkJoinWorkerThread w) {
- int idx = w.poolIndex;
- // Locking helps method recordWorker avoid unnecessary expansion
- final ReentrantLock lock = this.workerLock;
+ private boolean tryAwaitWork(ForkJoinWorkerThread w, long c) {
+ int v = w.eventCount;
+ w.nextWait = (int)c; // w's successor record
+ long nc = (long)(v & E_MASK) | ((c - AC_UNIT) & (AC_MASK|TC_MASK));
+ if (ctl != c || !UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
+ long d = ctl; // return true if lost to a deq, to force scan
+ return (int)d != (int)c && ((d - c) & AC_MASK) >= 0L;
+ }
+ for (int sc = w.stealCount; sc != 0;) { // accumulate stealCount
+ long s = stealCount;
+ if (UNSAFE.compareAndSwapLong(this, stealCountOffset, s, s + sc))
+ sc = w.stealCount = 0;
+ else if (w.eventCount != v)
+ return true; // update next time
+ }
+ if (parallelism + (int)(nc >> AC_SHIFT) == 0 &&
+ blockedCount == 0 && quiescerCount == 0)
+ idleAwaitWork(w, nc, c, v); // quiescent
+ for (boolean rescanned = false;;) {
+ if (w.eventCount != v)
+ return true;
+ if (!rescanned) {
+ int g = scanGuard, m = g & SMASK;
+ ForkJoinWorkerThread[] ws = workers;
+ if (ws != null && m < ws.length) {
+ rescanned = true;
+ for (int i = 0; i <= m; ++i) {
+ ForkJoinWorkerThread u = ws[i];
+ if (u != null) {
+ if (u.queueBase != u.queueTop &&
+ !tryReleaseWaiter())
+ rescanned = false; // contended
+ if (w.eventCount != v)
+ return true;
+ }
+ }
+ }
+ if (scanGuard != g || // stale
+ (queueBase != queueTop && !tryReleaseWaiter()))
+ rescanned = false;
+ if (!rescanned)
+ Thread.yield(); // reduce contention
+ else
+ Thread.interrupted(); // clear before park
+ }
+ else {
+ w.parked = true; // must recheck
+ if (w.eventCount != v) {
+ w.parked = false;
+ return true;
+ }
+ LockSupport.park(this);
+ rescanned = w.parked = false;
+ }
+ }
+ }
+
+ /**
+ * If inactivating worker w has caused pool to become
+ * quiescent, check for pool termination, and wait for event
+ * for up to SHRINK_RATE nanosecs (rescans are unnecessary in
+ * this case because quiescence reflects consensus about lack
+ * of work). On timeout, if ctl has not changed, terminate the
+ * worker. Upon its termination (see deregisterWorker), it may
+ * wake up another worker to possibly repeat this process.
+ *
+ * @param w the calling worker
+ * @param currentCtl the ctl value after enqueuing w
+ * @param prevCtl the ctl value if w terminated
+ * @param v the eventCount w awaits change
+ */
+ private void idleAwaitWork(ForkJoinWorkerThread w, long currentCtl,
+ long prevCtl, int v) {
+ if (w.eventCount == v) {
+ if (shutdown)
+ tryTerminate(false);
+ ForkJoinTask.helpExpungeStaleExceptions(); // help clean weak refs
+ while (ctl == currentCtl) {
+ long startTime = System.nanoTime();
+ w.parked = true;
+ if (w.eventCount == v) // must recheck
+ LockSupport.parkNanos(this, SHRINK_RATE);
+ w.parked = false;
+ if (w.eventCount != v)
+ break;
+ else if (System.nanoTime() - startTime < SHRINK_RATE)
+ Thread.interrupted(); // spurious wakeup
+ else if (UNSAFE.compareAndSwapLong(this, ctlOffset,
+ currentCtl, prevCtl)) {
+ w.terminate = true; // restore previous
+ w.eventCount = ((int)currentCtl + EC_UNIT) & E_MASK;
+ break;
+ }
+ }
+ }
+ }
+
+ // Submissions
+
+ /**
+ * Enqueues the given task in the submissionQueue. Same idea as
+ * ForkJoinWorkerThread.pushTask except for use of submissionLock.
+ *
+ * @param t the task
+ */
+ private void addSubmission(ForkJoinTask> t) {
+ final ReentrantLock lock = this.submissionLock;
lock.lock();
try {
- ForkJoinWorkerThread[] ws = workers;
- if (idx >= 0 && idx < ws.length && ws[idx] == w) // verify
- ws[idx] = null;
+ ForkJoinTask>[] q; int s, m;
+ if ((q = submissionQueue) != null) { // ignore if queue removed
+ long u = (((s = queueTop) & (m = q.length-1)) << ASHIFT)+ABASE;
+ UNSAFE.putOrderedObject(q, u, t);
+ queueTop = s + 1;
+ if (s - queueBase == m)
+ growSubmissionQueue();
+ }
} finally {
lock.unlock();
}
+ signalWork();
+ }
+
+ // (pollSubmission is defined below with exported methods)
+
+ /**
+ * Creates or doubles submissionQueue array.
+ * Basically identical to ForkJoinWorkerThread version.
+ */
+ private void growSubmissionQueue() {
+ ForkJoinTask>[] oldQ = submissionQueue;
+ int size = oldQ != null ? oldQ.length << 1 : INITIAL_QUEUE_CAPACITY;
+ if (size > MAXIMUM_QUEUE_CAPACITY)
+ throw new RejectedExecutionException("Queue capacity exceeded");
+ if (size < INITIAL_QUEUE_CAPACITY)
+ size = INITIAL_QUEUE_CAPACITY;
+ ForkJoinTask>[] q = submissionQueue = new ForkJoinTask>[size];
+ int mask = size - 1;
+ int top = queueTop;
+ int oldMask;
+ if (oldQ != null && (oldMask = oldQ.length - 1) >= 0) {
+ for (int b = queueBase; b != top; ++b) {
+ long u = ((b & oldMask) << ASHIFT) + ABASE;
+ Object x = UNSAFE.getObjectVolatile(oldQ, u);
+ if (x != null && UNSAFE.compareAndSwapObject(oldQ, u, x, null))
+ UNSAFE.putObjectVolatile
+ (q, ((b & mask) << ASHIFT) + ABASE, x);
+ }
+ }
+ }
+
+ // Blocking support
+
+ /**
+ * Tries to increment blockedCount, decrement active count
+ * (sometimes implicitly) and possibly release or create a
+ * compensating worker in preparation for blocking. Fails
+ * on contention or termination.
+ *
+ * @return true if the caller can block, else should recheck and retry
+ */
+ private boolean tryPreBlock() {
+ int b = blockedCount;
+ if (UNSAFE.compareAndSwapInt(this, blockedCountOffset, b, b + 1)) {
+ int pc = parallelism;
+ do {
+ ForkJoinWorkerThread[] ws; ForkJoinWorkerThread w;
+ int e, ac, tc, rc, i;
+ long c = ctl;
+ int u = (int)(c >>> 32);
+ if ((e = (int)c) < 0) {
+ // skip -- terminating
+ }
+ else if ((ac = (u >> UAC_SHIFT)) <= 0 && e != 0 &&
+ (ws = workers) != null &&
+ (i = ~e & SMASK) < ws.length &&
+ (w = ws[i]) != null) {
+ long nc = ((long)(w.nextWait & E_MASK) |
+ (c & (AC_MASK|TC_MASK)));
+ if (w.eventCount == e &&
+ UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
+ w.eventCount = (e + EC_UNIT) & E_MASK;
+ if (w.parked)
+ UNSAFE.unpark(w);
+ return true; // release an idle worker
+ }
+ }
+ else if ((tc = (short)(u >>> UTC_SHIFT)) >= 0 && ac + pc > 1) {
+ long nc = ((c - AC_UNIT) & AC_MASK) | (c & ~AC_MASK);
+ if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc))
+ return true; // no compensation needed
+ }
+ else if (tc + pc < MAX_ID) {
+ long nc = ((c + TC_UNIT) & TC_MASK) | (c & ~TC_MASK);
+ if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
+ addWorker();
+ return true; // create a replacement
+ }
+ }
+ // try to back out on any failure and let caller retry
+ } while (!UNSAFE.compareAndSwapInt(this, blockedCountOffset,
+ b = blockedCount, b - 1));
+ }
+ return false;
+ }
+
+ /**
+ * Decrements blockedCount and increments active count
+ */
+ private void postBlock() {
+ long c;
+ do {} while (!UNSAFE.compareAndSwapLong(this, ctlOffset, // no mask
+ c = ctl, c + AC_UNIT));
+ int b;
+ do {} while(!UNSAFE.compareAndSwapInt(this, blockedCountOffset,
+ b = blockedCount, b - 1));
+ }
+
+ /**
+ * Possibly blocks waiting for the given task to complete, or
+ * cancels the task if terminating. Fails to wait if contended.
+ *
+ * @param joinMe the task
+ */
+ final void tryAwaitJoin(ForkJoinTask> joinMe) {
+ int s;
+ Thread.interrupted(); // clear interrupts before checking termination
+ if (joinMe.status >= 0) {
+ if (tryPreBlock()) {
+ joinMe.tryAwaitDone(0L);
+ postBlock();
+ }
+ else if ((ctl & STOP_BIT) != 0L)
+ joinMe.cancelIgnoringExceptions();
+ }
+ }
+
+ /**
+ * Possibly blocks the given worker waiting for joinMe to
+ * complete or timeout
+ *
+ * @param joinMe the task
+ * @param millis the wait time for underlying Object.wait
+ */
+ final void timedAwaitJoin(ForkJoinTask> joinMe, long nanos) {
+ while (joinMe.status >= 0) {
+ Thread.interrupted();
+ if ((ctl & STOP_BIT) != 0L) {
+ joinMe.cancelIgnoringExceptions();
+ break;
+ }
+ if (tryPreBlock()) {
+ long last = System.nanoTime();
+ while (joinMe.status >= 0) {
+ long millis = TimeUnit.NANOSECONDS.toMillis(nanos);
+ if (millis <= 0)
+ break;
+ joinMe.tryAwaitDone(millis);
+ if (joinMe.status < 0)
+ break;
+ if ((ctl & STOP_BIT) != 0L) {
+ joinMe.cancelIgnoringExceptions();
+ break;
+ }
+ long now = System.nanoTime();
+ nanos -= now - last;
+ last = now;
+ }
+ postBlock();
+ break;
+ }
+ }
+ }
+
+ /**
+ * If necessary, compensates for blocker, and blocks
+ */
+ private void awaitBlocker(ManagedBlocker blocker)
+ throws InterruptedException {
+ while (!blocker.isReleasable()) {
+ if (tryPreBlock()) {
+ try {
+ do {} while (!blocker.isReleasable() && !blocker.block());
+ } finally {
+ postBlock();
+ }
+ break;
+ }
+ }
+ }
+
+ // Creating, registering and deregistring workers
+
+ /**
+ * Tries to create and start a worker; minimally rolls back counts
+ * on failure.
+ */
+ private void addWorker() {
+ Throwable ex = null;
+ ForkJoinWorkerThread t = null;
+ try {
+ t = factory.newThread(this);
+ } catch (Throwable e) {
+ ex = e;
+ }
+ if (t == null) { // null or exceptional factory return
+ long c; // adjust counts
+ do {} while (!UNSAFE.compareAndSwapLong
+ (this, ctlOffset, c = ctl,
+ (((c - AC_UNIT) & AC_MASK) |
+ ((c - TC_UNIT) & TC_MASK) |
+ (c & ~(AC_MASK|TC_MASK)))));
+ // Propagate exception if originating from an external caller
+ if (!tryTerminate(false) && ex != null &&
+ !(Thread.currentThread() instanceof ForkJoinWorkerThread))
+ UNSAFE.throwException(ex);
+ }
+ else
+ t.start();
+ }
+
+ /**
+ * Callback from ForkJoinWorkerThread constructor to assign a
+ * public name
+ */
+ final String nextWorkerName() {
+ for (int n;;) {
+ if (UNSAFE.compareAndSwapInt(this, nextWorkerNumberOffset,
+ n = nextWorkerNumber, ++n))
+ return workerNamePrefix + n;
+ }
+ }
+
+ /**
+ * Callback from ForkJoinWorkerThread constructor to
+ * determine its poolIndex and record in workers array.
+ *
+ * @param w the worker
+ * @return the worker's pool index
+ */
+ final int registerWorker(ForkJoinWorkerThread w) {
+ /*
+ * In the typical case, a new worker acquires the lock, uses
+ * next available index and returns quickly. Since we should
+ * not block callers (ultimately from signalWork or
+ * tryPreBlock) waiting for the lock needed to do this, we
+ * instead help release other workers while waiting for the
+ * lock.
+ */
+ for (int g;;) {
+ ForkJoinWorkerThread[] ws;
+ if (((g = scanGuard) & SG_UNIT) == 0 &&
+ UNSAFE.compareAndSwapInt(this, scanGuardOffset,
+ g, g | SG_UNIT)) {
+ int k = nextWorkerIndex;
+ try {
+ if ((ws = workers) != null) { // ignore on shutdown
+ int n = ws.length;
+ if (k < 0 || k >= n || ws[k] != null) {
+ for (k = 0; k < n && ws[k] != null; ++k)
+ ;
+ if (k == n)
+ ws = workers = Arrays.copyOf(ws, n << 1);
+ }
+ ws[k] = w;
+ nextWorkerIndex = k + 1;
+ int m = g & SMASK;
+ g = k >= m? ((m << 1) + 1) & SMASK : g + (SG_UNIT<<1);
+ }
+ } finally {
+ scanGuard = g;
+ }
+ return k;
+ }
+ else if ((ws = workers) != null) { // help release others
+ for (ForkJoinWorkerThread u : ws) {
+ if (u != null && u.queueBase != u.queueTop) {
+ if (tryReleaseWaiter())
+ break;
+ }
+ }
+ }
+ }
}
/**
@@ -743,415 +1200,46 @@ public class ForkJoinPool extends AbstractExecutorService {
*
* @param w the worker
*/
- final void workerTerminated(ForkJoinWorkerThread w) {
- forgetWorker(w);
- decrementWorkerCounts(w.isTrimmed() ? 0 : ONE_RUNNING, ONE_TOTAL);
- while (w.stealCount != 0) // collect final count
- tryAccumulateStealCount(w);
- tryTerminate(false);
- }
-
- // Waiting for and signalling events
-
- /**
- * Releases workers blocked on a count not equal to current count.
- * Normally called after precheck that eventWaiters isn't zero to
- * avoid wasted array checks. Gives up upon a change in count or
- * upon releasing four workers, letting others take over.
- */
- private void releaseEventWaiters() {
- ForkJoinWorkerThread[] ws = workers;
- int n = ws.length;
- long h = eventWaiters;
- int ec = eventCount;
- int releases = 4;
- ForkJoinWorkerThread w; int id;
- while ((id = (((int)h) & WAITER_ID_MASK) - 1) >= 0 &&
- (int)(h >>> EVENT_COUNT_SHIFT) != ec &&
- id < n && (w = ws[id]) != null) {
- if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset,
- h, w.nextWaiter)) {
- LockSupport.unpark(w);
- if (--releases == 0)
- break;
+ final void deregisterWorker(ForkJoinWorkerThread w, Throwable ex) {
+ int idx = w.poolIndex;
+ int sc = w.stealCount;
+ int steps = 0;
+ // Remove from array, adjust worker counts and collect steal count.
+ // We can intermix failed removes or adjusts with steal updates
+ do {
+ long s, c;
+ int g;
+ if (steps == 0 && ((g = scanGuard) & SG_UNIT) == 0 &&
+ UNSAFE.compareAndSwapInt(this, scanGuardOffset,
+ g, g |= SG_UNIT)) {
+ ForkJoinWorkerThread[] ws = workers;
+ if (ws != null && idx >= 0 &&
+ idx < ws.length && ws[idx] == w)
+ ws[idx] = null; // verify
+ nextWorkerIndex = idx;
+ scanGuard = g + SG_UNIT;
+ steps = 1;
}
- if (eventCount != ec)
- break;
- h = eventWaiters;
+ if (steps == 1 &&
+ UNSAFE.compareAndSwapLong(this, ctlOffset, c = ctl,
+ (((c - AC_UNIT) & AC_MASK) |
+ ((c - TC_UNIT) & TC_MASK) |
+ (c & ~(AC_MASK|TC_MASK)))))
+ steps = 2;
+ if (sc != 0 &&
+ UNSAFE.compareAndSwapLong(this, stealCountOffset,
+ s = stealCount, s + sc))
+ sc = 0;
+ } while (steps != 2 || sc != 0);
+ if (!tryTerminate(false)) {
+ if (ex != null) // possibly replace if died abnormally
+ signalWork();
+ else
+ tryReleaseWaiter();
}
}
- /**
- * Tries to advance eventCount and releases waiters. Called only
- * from workers.
- */
- final void signalWork() {
- int c; // try to increment event count -- CAS failure OK
- UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1);
- if (eventWaiters != 0L)
- releaseEventWaiters();
- }
-
- /**
- * Adds the given worker to event queue and blocks until
- * terminating or event count advances from the given value
- *
- * @param w the calling worker thread
- * @param ec the count
- */
- private void eventSync(ForkJoinWorkerThread w, int ec) {
- long nh = (((long)ec) << EVENT_COUNT_SHIFT) | ((long)(w.poolIndex+1));
- long h;
- while ((runState < SHUTDOWN || !tryTerminate(false)) &&
- (((int)(h = eventWaiters) & WAITER_ID_MASK) == 0 ||
- (int)(h >>> EVENT_COUNT_SHIFT) == ec) &&
- eventCount == ec) {
- if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset,
- w.nextWaiter = h, nh)) {
- awaitEvent(w, ec);
- break;
- }
- }
- }
-
- /**
- * Blocks the given worker (that has already been entered as an
- * event waiter) until terminating or event count advances from
- * the given value. The oldest (first) waiter uses a timed wait to
- * occasionally one-by-one shrink the number of workers (to a
- * minimum of one) if the pool has not been used for extended
- * periods.
- *
- * @param w the calling worker thread
- * @param ec the count
- */
- private void awaitEvent(ForkJoinWorkerThread w, int ec) {
- while (eventCount == ec) {
- if (tryAccumulateStealCount(w)) { // transfer while idle
- boolean untimed = (w.nextWaiter != 0L ||
- (workerCounts & RUNNING_COUNT_MASK) <= 1);
- long startTime = untimed ? 0 : System.nanoTime();
- Thread.interrupted(); // clear/ignore interrupt
- if (w.isTerminating() || eventCount != ec)
- break; // recheck after clear
- if (untimed)
- LockSupport.park(w);
- else {
- LockSupport.parkNanos(w, SHRINK_RATE_NANOS);
- if (eventCount != ec || w.isTerminating())
- break;
- if (System.nanoTime() - startTime >= SHRINK_RATE_NANOS)
- tryShutdownUnusedWorker(ec);
- }
- }
- }
- }
-
- // Maintaining parallelism
-
- /**
- * Pushes worker onto the spare stack.
- */
- final void pushSpare(ForkJoinWorkerThread w) {
- int ns = (++w.spareCount << SPARE_COUNT_SHIFT) | (w.poolIndex + 1);
- do {} while (!UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
- w.nextSpare = spareWaiters,ns));
- }
-
- /**
- * Tries (once) to resume a spare if the number of running
- * threads is less than target.
- */
- private void tryResumeSpare() {
- int sw, id;
- ForkJoinWorkerThread[] ws = workers;
- int n = ws.length;
- ForkJoinWorkerThread w;
- if ((sw = spareWaiters) != 0 &&
- (id = (sw & SPARE_ID_MASK) - 1) >= 0 &&
- id < n && (w = ws[id]) != null &&
- (runState >= TERMINATING ||
- (workerCounts & RUNNING_COUNT_MASK) < parallelism) &&
- spareWaiters == sw &&
- UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
- sw, w.nextSpare)) {
- int c; // increment running count before resume
- do {} while (!UNSAFE.compareAndSwapInt
- (this, workerCountsOffset,
- c = workerCounts, c + ONE_RUNNING));
- if (w.tryUnsuspend())
- LockSupport.unpark(w);
- else // back out if w was shutdown
- decrementWorkerCounts(ONE_RUNNING, 0);
- }
- }
-
- /**
- * Tries to increase the number of running workers if below target
- * parallelism: If a spare exists tries to resume it via
- * tryResumeSpare. Otherwise, if not enough total workers or all
- * existing workers are busy, adds a new worker. In all cases also
- * helps wake up releasable workers waiting for work.
- */
- private void helpMaintainParallelism() {
- int pc = parallelism;
- int wc, rs, tc;
- while (((wc = workerCounts) & RUNNING_COUNT_MASK) < pc &&
- (rs = runState) < TERMINATING) {
- if (spareWaiters != 0)
- tryResumeSpare();
- else if ((tc = wc >>> TOTAL_COUNT_SHIFT) >= MAX_WORKERS ||
- (tc >= pc && (rs & ACTIVE_COUNT_MASK) != tc))
- break; // enough total
- else if (runState == rs && workerCounts == wc &&
- UNSAFE.compareAndSwapInt(this, workerCountsOffset, wc,
- wc + (ONE_RUNNING|ONE_TOTAL))) {
- ForkJoinWorkerThread w = null;
- Throwable fail = null;
- try {
- w = factory.newThread(this);
- } catch (Throwable ex) {
- fail = ex;
- }
- if (w == null) { // null or exceptional factory return
- decrementWorkerCounts(ONE_RUNNING, ONE_TOTAL);
- tryTerminate(false); // handle failure during shutdown
- // If originating from an external caller,
- // propagate exception, else ignore
- if (fail != null && runState < TERMINATING &&
- !(Thread.currentThread() instanceof
- ForkJoinWorkerThread))
- UNSAFE.throwException(fail);
- break;
- }
- w.start(recordWorker(w), ueh);
- if ((workerCounts >>> TOTAL_COUNT_SHIFT) >= pc)
- break; // add at most one unless total below target
- }
- }
- if (eventWaiters != 0L)
- releaseEventWaiters();
- }
-
- /**
- * Callback from the oldest waiter in awaitEvent waking up after a
- * period of non-use. If all workers are idle, tries (once) to
- * shutdown an event waiter or a spare, if one exists. Note that
- * we don't need CAS or locks here because the method is called
- * only from one thread occasionally waking (and even misfires are
- * OK). Note that until the shutdown worker fully terminates,
- * workerCounts will overestimate total count, which is tolerable.
- *
- * @param ec the event count waited on by caller (to abort
- * attempt if count has since changed).
- */
- private void tryShutdownUnusedWorker(int ec) {
- if (runState == 0 && eventCount == ec) { // only trigger if all idle
- ForkJoinWorkerThread[] ws = workers;
- int n = ws.length;
- ForkJoinWorkerThread w = null;
- boolean shutdown = false;
- int sw;
- long h;
- if ((sw = spareWaiters) != 0) { // prefer killing spares
- int id = (sw & SPARE_ID_MASK) - 1;
- if (id >= 0 && id < n && (w = ws[id]) != null &&
- UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
- sw, w.nextSpare))
- shutdown = true;
- }
- else if ((h = eventWaiters) != 0L) {
- long nh;
- int id = (((int)h) & WAITER_ID_MASK) - 1;
- if (id >= 0 && id < n && (w = ws[id]) != null &&
- (nh = w.nextWaiter) != 0L && // keep at least one worker
- UNSAFE.compareAndSwapLong(this, eventWaitersOffset, h, nh))
- shutdown = true;
- }
- if (w != null && shutdown) {
- w.shutdown();
- LockSupport.unpark(w);
- }
- }
- releaseEventWaiters(); // in case of interference
- }
-
- /**
- * Callback from workers invoked upon each top-level action (i.e.,
- * stealing a task or taking a submission and running it).
- * Performs one or more of the following:
- *
- * 1. If the worker is active and either did not run a task
- * or there are too many workers, try to set its active status
- * to inactive and update activeCount. On contention, we may
- * try again in this or a subsequent call.
- *
- * 2. If not enough total workers, help create some.
- *
- * 3. If there are too many running workers, suspend this worker
- * (first forcing inactive if necessary). If it is not needed,
- * it may be shutdown while suspended (via
- * tryShutdownUnusedWorker). Otherwise, upon resume it
- * rechecks running thread count and need for event sync.
- *
- * 4. If worker did not run a task, await the next task event via
- * eventSync if necessary (first forcing inactivation), upon
- * which the worker may be shutdown via
- * tryShutdownUnusedWorker. Otherwise, help release any
- * existing event waiters that are now releasable,
- *
- * @param w the worker
- * @param ran true if worker ran a task since last call to this method
- */
- final void preStep(ForkJoinWorkerThread w, boolean ran) {
- int wec = w.lastEventCount;
- boolean active = w.active;
- boolean inactivate = false;
- int pc = parallelism;
- while (w.runState == 0) {
- int rs = runState;
- if (rs >= TERMINATING) { // propagate shutdown
- w.shutdown();
- break;
- }
- if ((inactivate || (active && (rs & ACTIVE_COUNT_MASK) >= pc)) &&
- UNSAFE.compareAndSwapInt(this, runStateOffset, rs, --rs)) {
- inactivate = active = w.active = false;
- if (rs == SHUTDOWN) { // all inactive and shut down
- tryTerminate(false);
- continue;
- }
- }
- int wc = workerCounts; // try to suspend as spare
- if ((wc & RUNNING_COUNT_MASK) > pc) {
- if (!(inactivate |= active) && // must inactivate to suspend
- workerCounts == wc &&
- UNSAFE.compareAndSwapInt(this, workerCountsOffset,
- wc, wc - ONE_RUNNING))
- w.suspendAsSpare();
- }
- else if ((wc >>> TOTAL_COUNT_SHIFT) < pc)
- helpMaintainParallelism(); // not enough workers
- else if (ran)
- break;
- else {
- long h = eventWaiters;
- int ec = eventCount;
- if (h != 0L && (int)(h >>> EVENT_COUNT_SHIFT) != ec)
- releaseEventWaiters(); // release others before waiting
- else if (ec != wec) {
- w.lastEventCount = ec; // no need to wait
- break;
- }
- else if (!(inactivate |= active))
- eventSync(w, wec); // must inactivate before sync
- }
- }
- }
-
- /**
- * Helps and/or blocks awaiting join of the given task.
- * See above for explanation.
- *
- * @param joinMe the task to join
- * @param worker the current worker thread
- * @param timed true if wait should time out
- * @param nanos timeout value if timed
- */
- final void awaitJoin(ForkJoinTask> joinMe, ForkJoinWorkerThread worker,
- boolean timed, long nanos) {
- long startTime = timed ? System.nanoTime() : 0L;
- int retries = 2 + (parallelism >> 2); // #helpJoins before blocking
- boolean running = true; // false when count decremented
- while (joinMe.status >= 0) {
- if (runState >= TERMINATING) {
- joinMe.cancelIgnoringExceptions();
- break;
- }
- running = worker.helpJoinTask(joinMe, running);
- if (joinMe.status < 0)
- break;
- if (retries > 0) {
- --retries;
- continue;
- }
- int wc = workerCounts;
- if ((wc & RUNNING_COUNT_MASK) != 0) {
- if (running) {
- if (!UNSAFE.compareAndSwapInt(this, workerCountsOffset,
- wc, wc - ONE_RUNNING))
- continue;
- running = false;
- }
- long h = eventWaiters;
- if (h != 0L && (int)(h >>> EVENT_COUNT_SHIFT) != eventCount)
- releaseEventWaiters();
- if ((workerCounts & RUNNING_COUNT_MASK) != 0) {
- long ms; int ns;
- if (!timed) {
- ms = JOIN_TIMEOUT_MILLIS;
- ns = 0;
- }
- else { // at most JOIN_TIMEOUT_MILLIS per wait
- long nt = nanos - (System.nanoTime() - startTime);
- if (nt <= 0L)
- break;
- ms = nt / 1000000;
- if (ms > JOIN_TIMEOUT_MILLIS) {
- ms = JOIN_TIMEOUT_MILLIS;
- ns = 0;
- }
- else
- ns = (int) (nt % 1000000);
- }
- joinMe.internalAwaitDone(ms, ns);
- }
- if (joinMe.status < 0)
- break;
- }
- helpMaintainParallelism();
- }
- if (!running) {
- int c;
- do {} while (!UNSAFE.compareAndSwapInt
- (this, workerCountsOffset,
- c = workerCounts, c + ONE_RUNNING));
- }
- }
-
- /**
- * Same idea as awaitJoin, but no helping, retries, or timeouts.
- */
- final void awaitBlocker(ManagedBlocker blocker)
- throws InterruptedException {
- while (!blocker.isReleasable()) {
- int wc = workerCounts;
- if ((wc & RUNNING_COUNT_MASK) == 0)
- helpMaintainParallelism();
- else if (UNSAFE.compareAndSwapInt(this, workerCountsOffset,
- wc, wc - ONE_RUNNING)) {
- try {
- while (!blocker.isReleasable()) {
- long h = eventWaiters;
- if (h != 0L &&
- (int)(h >>> EVENT_COUNT_SHIFT) != eventCount)
- releaseEventWaiters();
- else if ((workerCounts & RUNNING_COUNT_MASK) == 0 &&
- runState < TERMINATING)
- helpMaintainParallelism();
- else if (blocker.block())
- break;
- }
- } finally {
- int c;
- do {} while (!UNSAFE.compareAndSwapInt
- (this, workerCountsOffset,
- c = workerCounts, c + ONE_RUNNING));
- }
- break;
- }
- }
- }
+ // Shutdown and termination
/**
* Possibly initiates and/or completes termination.
@@ -1161,97 +1249,132 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return true if now terminating or terminated
*/
private boolean tryTerminate(boolean now) {
- if (now)
- advanceRunLevel(SHUTDOWN); // ensure at least SHUTDOWN
- else if (runState < SHUTDOWN ||
- !submissionQueue.isEmpty() ||
- (runState & ACTIVE_COUNT_MASK) != 0)
- return false;
-
- if (advanceRunLevel(TERMINATING))
- startTerminating();
-
- // Finish now if all threads terminated; else in some subsequent call
- if ((workerCounts >>> TOTAL_COUNT_SHIFT) == 0) {
- advanceRunLevel(TERMINATED);
- termination.forceTermination();
+ long c;
+ while (((c = ctl) & STOP_BIT) == 0) {
+ if (!now) {
+ if ((int)(c >> AC_SHIFT) != -parallelism)
+ return false;
+ if (!shutdown || blockedCount != 0 || quiescerCount != 0 ||
+ queueBase != queueTop) {
+ if (ctl == c) // staleness check
+ return false;
+ continue;
+ }
+ }
+ if (UNSAFE.compareAndSwapLong(this, ctlOffset, c, c | STOP_BIT))
+ startTerminating();
+ }
+ if ((short)(c >>> TC_SHIFT) == -parallelism) { // signal when 0 workers
+ final ReentrantLock lock = this.submissionLock;
+ lock.lock();
+ try {
+ termination.signalAll();
+ } finally {
+ lock.unlock();
+ }
}
return true;
}
/**
- * Actions on transition to TERMINATING
- *
- * Runs up to four passes through workers: (0) shutting down each
- * (without waking up if parked) to quickly spread notifications
- * without unnecessary bouncing around event queues etc (1) wake
- * up and help cancel tasks (2) interrupt (3) mop up races with
- * interrupted workers
+ * Runs up to three passes through workers: (0) Setting
+ * termination status for each worker, followed by wakeups up to
+ * queued workers; (1) helping cancel 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.
*/
private void startTerminating() {
cancelSubmissions();
- for (int passes = 0; passes < 4 && workerCounts != 0; ++passes) {
- int c; // advance event count
- UNSAFE.compareAndSwapInt(this, eventCountOffset,
- c = eventCount, c+1);
- eventWaiters = 0L; // clobber lists
- spareWaiters = 0;
- for (ForkJoinWorkerThread w : workers) {
- if (w != null) {
- w.shutdown();
- if (passes > 0 && !w.isTerminated()) {
- w.cancelTasks();
- LockSupport.unpark(w);
- if (passes > 1 && !w.isInterrupted()) {
- try {
- w.interrupt();
- } catch (SecurityException ignore) {
+ for (int pass = 0; pass < 3; ++pass) {
+ ForkJoinWorkerThread[] ws = workers;
+ if (ws != null) {
+ for (ForkJoinWorkerThread w : ws) {
+ if (w != null) {
+ w.terminate = true;
+ if (pass > 0) {
+ w.cancelTasks();
+ if (pass > 1 && !w.isInterrupted()) {
+ try {
+ w.interrupt();
+ } catch (SecurityException ignore) {
+ }
}
}
}
}
+ terminateWaiters();
+ }
+ }
+ }
+
+ /**
+ * Polls and cancels all submissions. Called only during termination.
+ */
+ private void cancelSubmissions() {
+ while (queueBase != queueTop) {
+ ForkJoinTask> task = pollSubmission();
+ if (task != null) {
+ try {
+ task.cancel(false);
+ } catch (Throwable ignore) {
+ }
}
}
}
/**
- * Clears out and cancels submissions, ignoring exceptions.
+ * Tries to set the termination status of waiting workers, and
+ * then wakes them up (after which they will terminate).
*/
- private void cancelSubmissions() {
- ForkJoinTask> task;
- while ((task = submissionQueue.poll()) != null) {
- try {
- task.cancel(false);
- } catch (Throwable ignore) {
+ private void terminateWaiters() {
+ ForkJoinWorkerThread[] ws = workers;
+ if (ws != null) {
+ ForkJoinWorkerThread w; long c; int i, e;
+ int n = ws.length;
+ while ((i = ~(e = (int)(c = ctl)) & SMASK) < n &&
+ (w = ws[i]) != null && w.eventCount == (e & E_MASK)) {
+ if (UNSAFE.compareAndSwapLong(this, ctlOffset, c,
+ (long)(w.nextWait & E_MASK) |
+ ((c + AC_UNIT) & AC_MASK) |
+ (c & (TC_MASK|STOP_BIT)))) {
+ w.terminate = true;
+ w.eventCount = e + EC_UNIT;
+ if (w.parked)
+ UNSAFE.unpark(w);
+ }
}
}
}
- // misc support for ForkJoinWorkerThread
+ // misc ForkJoinWorkerThread support
/**
- * Returns pool number.
+ * Increment or decrement quiescerCount. Needed only to prevent
+ * triggering shutdown if a worker is transiently inactive while
+ * checking quiescence.
+ *
+ * @param delta 1 for increment, -1 for decrement
*/
- final int getPoolNumber() {
- return poolNumber;
+ final void addQuiescerCount(int delta) {
+ int c;
+ do {} while(!UNSAFE.compareAndSwapInt(this, quiescerCountOffset,
+ c = quiescerCount, c + delta));
}
/**
- * Tries to accumulate steal count from a worker, clearing
- * the worker's value if successful.
+ * Directly increment or decrement active count without
+ * queuing. This method is used to transiently assert inactivation
+ * while checking quiescence.
*
- * @return true if worker steal count now zero
+ * @param delta 1 for increment, -1 for decrement
*/
- final boolean tryAccumulateStealCount(ForkJoinWorkerThread w) {
- int sc = w.stealCount;
- long c = stealCount;
- // CAS even if zero, for fence effects
- if (UNSAFE.compareAndSwapLong(this, stealCountOffset, c, c + sc)) {
- if (sc != 0)
- w.stealCount = 0;
- return true;
- }
- return sc == 0;
+ final void addActiveCount(int delta) {
+ long d = delta < 0 ? -AC_UNIT : AC_UNIT;
+ long c;
+ do {} while (!UNSAFE.compareAndSwapLong(this, ctlOffset, c = ctl,
+ ((c + d) & AC_MASK) |
+ (c & ~AC_MASK)));
}
/**
@@ -1259,16 +1382,17 @@ public class ForkJoinPool extends AbstractExecutorService {
* active thread.
*/
final int idlePerActive() {
- int pc = parallelism; // use parallelism, not rc
- int ac = runState; // no mask -- artificially boosts during shutdown
- // Use exact results for small values, saturate past 4
- return ((pc <= ac) ? 0 :
- (pc >>> 1 <= ac) ? 1 :
- (pc >>> 2 <= ac) ? 3 :
- pc >>> 3);
+ // Approximate at powers of two for small values, saturate past 4
+ int p = parallelism;
+ int a = p + (int)(ctl >> AC_SHIFT);
+ return (a > (p >>>= 1) ? 0 :
+ a > (p >>>= 1) ? 1 :
+ a > (p >>>= 1) ? 2 :
+ a > (p >>>= 1) ? 4 :
+ 8);
}
- // Public and protected methods
+ // Exported methods
// Constructors
@@ -1337,49 +1461,42 @@ public class ForkJoinPool extends AbstractExecutorService {
checkPermission();
if (factory == null)
throw new NullPointerException();
- if (parallelism <= 0 || parallelism > MAX_WORKERS)
+ if (parallelism <= 0 || parallelism > MAX_ID)
throw new IllegalArgumentException();
this.parallelism = parallelism;
this.factory = factory;
this.ueh = handler;
this.locallyFifo = asyncMode;
- int arraySize = initialArraySizeFor(parallelism);
- this.workers = new ForkJoinWorkerThread[arraySize];
- this.submissionQueue = new LinkedTransferQueue>();
- this.workerLock = new ReentrantLock();
- this.termination = new Phaser(1);
- this.poolNumber = poolNumberGenerator.incrementAndGet();
- }
-
- /**
- * Returns initial power of two size for workers array.
- * @param pc the initial parallelism level
- */
- private static int initialArraySizeFor(int pc) {
- // If possible, initially allocate enough space for one spare
- int size = pc < MAX_WORKERS ? pc + 1 : MAX_WORKERS;
- // See Hackers Delight, sec 3.2. We know MAX_WORKERS < (1 >>> 16)
- size |= size >>> 1;
- size |= size >>> 2;
- size |= size >>> 4;
- size |= size >>> 8;
- return size + 1;
+ long np = (long)(-parallelism); // offset ctl counts
+ this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
+ this.submissionQueue = new ForkJoinTask>[INITIAL_QUEUE_CAPACITY];
+ // initialize workers array with room for 2*parallelism if possible
+ int n = parallelism << 1;
+ if (n >= MAX_ID)
+ n = MAX_ID;
+ else { // See Hackers Delight, sec 3.2, where n < (1 << 16)
+ n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8;
+ }
+ workers = new ForkJoinWorkerThread[n + 1];
+ this.submissionLock = new ReentrantLock();
+ this.termination = submissionLock.newCondition();
+ StringBuilder sb = new StringBuilder("ForkJoinPool-");
+ sb.append(poolNumberGenerator.incrementAndGet());
+ sb.append("-worker-");
+ this.workerNamePrefix = sb.toString();
}
// Execution methods
- /**
- * Submits task and creates, starts, or resumes some workers if necessary
- */
- private void doSubmit(ForkJoinTask task) {
- submissionQueue.offer(task);
- int c; // try to increment event count -- CAS failure OK
- UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1);
- helpMaintainParallelism();
- }
-
/**
* Performs the given task, returning its result upon completion.
+ * If the computation encounters an unchecked Exception or Error,
+ * it is rethrown as the outcome of this invocation. Rethrown
+ * exceptions behave in the same way as regular exceptions, but,
+ * when possible, contain stack traces (as displayed for example
+ * using {@code ex.printStackTrace()}) of both the current thread
+ * as well as the thread actually encountering the exception;
+ * minimally only the latter.
*
* @param task the task
* @return the task's result
@@ -1388,16 +1505,16 @@ public class ForkJoinPool extends AbstractExecutorService {
* scheduled for execution
*/
public T invoke(ForkJoinTask task) {
+ Thread t = Thread.currentThread();
if (task == null)
throw new NullPointerException();
- if (runState >= SHUTDOWN)
+ if (shutdown)
throw new RejectedExecutionException();
- Thread t = Thread.currentThread();
if ((t instanceof ForkJoinWorkerThread) &&
((ForkJoinWorkerThread)t).pool == this)
return task.invoke(); // bypass submit if in same pool
else {
- doSubmit(task);
+ addSubmission(task);
return task.join();
}
}
@@ -1407,14 +1524,15 @@ public class ForkJoinPool extends AbstractExecutorService {
* computation in the current pool, else submits as external task.
*/
private void forkOrSubmit(ForkJoinTask task) {
- if (runState >= SHUTDOWN)
- throw new RejectedExecutionException();
+ ForkJoinWorkerThread w;
Thread t = Thread.currentThread();
+ if (shutdown)
+ throw new RejectedExecutionException();
if ((t instanceof ForkJoinWorkerThread) &&
- ((ForkJoinWorkerThread)t).pool == this)
- task.fork();
+ (w = (ForkJoinWorkerThread)t).pool == this)
+ w.pushTask(task);
else
- doSubmit(task);
+ addSubmission(task);
}
/**
@@ -1571,7 +1689,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return the number of worker threads
*/
public int getPoolSize() {
- return workerCounts >>> TOTAL_COUNT_SHIFT;
+ return parallelism + (short)(ctl >>> TC_SHIFT);
}
/**
@@ -1593,7 +1711,8 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return the number of worker threads
*/
public int getRunningThreadCount() {
- return workerCounts & RUNNING_COUNT_MASK;
+ int r = parallelism + (int)(ctl >> AC_SHIFT);
+ return r <= 0? 0 : r; // suppress momentarily negative values
}
/**
@@ -1604,7 +1723,8 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return the number of active threads
*/
public int getActiveThreadCount() {
- return runState & ACTIVE_COUNT_MASK;
+ int r = parallelism + (int)(ctl >> AC_SHIFT) + blockedCount;
+ return r <= 0? 0 : r; // suppress momentarily negative values
}
/**
@@ -1619,7 +1739,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return {@code true} if all threads are currently idle
*/
public boolean isQuiescent() {
- return (runState & ACTIVE_COUNT_MASK) == 0;
+ return parallelism + (int)(ctl >> AC_SHIFT) + blockedCount == 0;
}
/**
@@ -1649,21 +1769,25 @@ public class ForkJoinPool extends AbstractExecutorService {
*/
public long getQueuedTaskCount() {
long count = 0;
- for (ForkJoinWorkerThread w : workers)
- if (w != null)
- count += w.getQueueSize();
+ ForkJoinWorkerThread[] ws;
+ if ((short)(ctl >>> TC_SHIFT) > -parallelism &&
+ (ws = workers) != null) {
+ for (ForkJoinWorkerThread w : ws)
+ if (w != null)
+ count -= w.queueBase - w.queueTop; // must read base first
+ }
return count;
}
/**
* Returns an estimate of the number of tasks submitted to this
- * pool that have not yet begun executing. This method takes time
- * proportional to the number of submissions.
+ * pool that have not yet begun executing. This method may take
+ * time proportional to the number of submissions.
*
* @return the number of queued submissions
*/
public int getQueuedSubmissionCount() {
- return submissionQueue.size();
+ return -queueBase + queueTop;
}
/**
@@ -1673,7 +1797,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return {@code true} if there are any queued submissions
*/
public boolean hasQueuedSubmissions() {
- return !submissionQueue.isEmpty();
+ return queueBase != queueTop;
}
/**
@@ -1684,7 +1808,19 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return the next submission, or {@code null} if none
*/
protected ForkJoinTask> pollSubmission() {
- return submissionQueue.poll();
+ ForkJoinTask> t; ForkJoinTask>[] q; int b, i;
+ while ((b = queueBase) != queueTop &&
+ (q = submissionQueue) != null &&
+ (i = (q.length - 1) & b) >= 0) {
+ long u = (i << ASHIFT) + ABASE;
+ if ((t = q[i]) != null &&
+ queueBase == b &&
+ UNSAFE.compareAndSwapObject(q, u, t, null)) {
+ queueBase = b + 1;
+ return t;
+ }
+ }
+ return null;
}
/**
@@ -1705,10 +1841,21 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return the number of elements transferred
*/
protected int drainTasksTo(Collection super ForkJoinTask>> c) {
- int count = submissionQueue.drainTo(c);
- for (ForkJoinWorkerThread w : workers)
- if (w != null)
- count += w.drainTasksTo(c);
+ int count = 0;
+ while (queueBase != queueTop) {
+ ForkJoinTask> t = pollSubmission();
+ if (t != null) {
+ c.add(t);
+ ++count;
+ }
+ }
+ ForkJoinWorkerThread[] ws;
+ if ((short)(ctl >>> TC_SHIFT) > -parallelism &&
+ (ws = workers) != null) {
+ for (ForkJoinWorkerThread w : ws)
+ if (w != null)
+ count += w.drainTasksTo(c);
+ }
return count;
}
@@ -1723,14 +1870,20 @@ public class ForkJoinPool extends AbstractExecutorService {
long st = getStealCount();
long qt = getQueuedTaskCount();
long qs = getQueuedSubmissionCount();
- int wc = workerCounts;
- int tc = wc >>> TOTAL_COUNT_SHIFT;
- int rc = wc & RUNNING_COUNT_MASK;
int pc = parallelism;
- int rs = runState;
- int ac = rs & ACTIVE_COUNT_MASK;
+ long c = ctl;
+ int tc = pc + (short)(c >>> TC_SHIFT);
+ int rc = pc + (int)(c >> AC_SHIFT);
+ if (rc < 0) // ignore transient negative
+ rc = 0;
+ int ac = rc + blockedCount;
+ String level;
+ if ((c & STOP_BIT) != 0)
+ level = (tc == 0)? "Terminated" : "Terminating";
+ else
+ level = shutdown? "Shutting down" : "Running";
return super.toString() +
- "[" + runLevelToString(rs) +
+ "[" + level +
", parallelism = " + pc +
", size = " + tc +
", active = " + ac +
@@ -1741,13 +1894,6 @@ public class ForkJoinPool extends AbstractExecutorService {
"]";
}
- private static String runLevelToString(int s) {
- return ((s & TERMINATED) != 0 ? "Terminated" :
- ((s & TERMINATING) != 0 ? "Terminating" :
- ((s & SHUTDOWN) != 0 ? "Shutting down" :
- "Running")));
- }
-
/**
* Initiates an orderly shutdown in which previously submitted
* tasks are executed, but no new tasks will be accepted.
@@ -1762,7 +1908,7 @@ public class ForkJoinPool extends AbstractExecutorService {
*/
public void shutdown() {
checkPermission();
- advanceRunLevel(SHUTDOWN);
+ shutdown = true;
tryTerminate(false);
}
@@ -1784,6 +1930,7 @@ public class ForkJoinPool extends AbstractExecutorService {
*/
public List shutdownNow() {
checkPermission();
+ shutdown = true;
tryTerminate(true);
return Collections.emptyList();
}
@@ -1794,7 +1941,9 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return {@code true} if all tasks have completed following shut down
*/
public boolean isTerminated() {
- return runState >= TERMINATED;
+ long c = ctl;
+ return ((c & STOP_BIT) != 0L &&
+ (short)(c >>> TC_SHIFT) == -parallelism);
}
/**
@@ -1811,14 +1960,16 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return {@code true} if terminating but not yet terminated
*/
public boolean isTerminating() {
- return (runState & (TERMINATING|TERMINATED)) == TERMINATING;
+ long c = ctl;
+ return ((c & STOP_BIT) != 0L &&
+ (short)(c >>> TC_SHIFT) != -parallelism);
}
/**
* Returns true if terminating or terminated. Used by ForkJoinWorkerThread.
*/
final boolean isAtLeastTerminating() {
- return runState >= TERMINATING;
+ return (ctl & STOP_BIT) != 0L;
}
/**
@@ -1827,7 +1978,7 @@ public class ForkJoinPool extends AbstractExecutorService {
* @return {@code true} if this pool has been shut down
*/
public boolean isShutdown() {
- return runState >= SHUTDOWN;
+ return shutdown;
}
/**
@@ -1843,12 +1994,20 @@ public class ForkJoinPool extends AbstractExecutorService {
*/
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
+ long nanos = unit.toNanos(timeout);
+ final ReentrantLock lock = this.submissionLock;
+ lock.lock();
try {
- termination.awaitAdvanceInterruptibly(0, timeout, unit);
- } catch (TimeoutException ex) {
- return false;
+ for (;;) {
+ if (isTerminated())
+ return true;
+ if (nanos <= 0)
+ return false;
+ nanos = termination.awaitNanos(nanos);
+ }
+ } finally {
+ lock.unlock();
}
- return true;
}
/**
@@ -1859,13 +2018,15 @@ public class ForkJoinPool extends AbstractExecutorService {
* {@code isReleasable} must return {@code true} if blocking is
* not necessary. Method {@code block} blocks the current thread
* if necessary (perhaps internally invoking {@code isReleasable}
- * before actually blocking). The unusual methods in this API
- * accommodate synchronizers that may, but don't usually, block
- * for long periods. Similarly, they allow more efficient internal
- * handling of cases in which additional workers may be, but
- * usually are not, needed to ensure sufficient parallelism.
- * Toward this end, implementations of method {@code isReleasable}
- * must be amenable to repeated invocation.
+ * before actually blocking). These actions are performed by any
+ * thread invoking {@link ForkJoinPool#managedBlock}. The
+ * unusual methods in this API accommodate synchronizers that may,
+ * but don't usually, block for long periods. Similarly, they
+ * allow more efficient internal handling of cases in which
+ * additional workers may be, but usually are not, needed to
+ * ensure sufficient parallelism. Toward this end,
+ * implementations of method {@code isReleasable} must be amenable
+ * to repeated invocation.
*
* For example, here is a ManagedBlocker based on a
* ReentrantLock:
@@ -1967,29 +2128,47 @@ public class ForkJoinPool extends AbstractExecutorService {
}
// Unsafe mechanics
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long ctlOffset;
+ private static final long stealCountOffset;
+ private static final long blockedCountOffset;
+ private static final long quiescerCountOffset;
+ private static final long scanGuardOffset;
+ private static final long nextWorkerNumberOffset;
+ private static final long ABASE;
+ private static final int ASHIFT;
- private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
- private static final long workerCountsOffset =
- objectFieldOffset("workerCounts", ForkJoinPool.class);
- private static final long runStateOffset =
- objectFieldOffset("runState", ForkJoinPool.class);
- private static final long eventCountOffset =
- objectFieldOffset("eventCount", ForkJoinPool.class);
- private static final long eventWaitersOffset =
- objectFieldOffset("eventWaiters", ForkJoinPool.class);
- private static final long stealCountOffset =
- objectFieldOffset("stealCount", ForkJoinPool.class);
- private static final long spareWaitersOffset =
- objectFieldOffset("spareWaiters", ForkJoinPool.class);
-
- private static long objectFieldOffset(String field, Class> klazz) {
+ static {
+ poolNumberGenerator = new AtomicInteger();
+ workerSeedGenerator = new Random();
+ modifyThreadPermission = new RuntimePermission("modifyThread");
+ defaultForkJoinWorkerThreadFactory =
+ new DefaultForkJoinWorkerThreadFactory();
+ int s;
try {
- return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
- } catch (NoSuchFieldException e) {
- // Convert Exception to corresponding Error
- NoSuchFieldError error = new NoSuchFieldError(field);
- error.initCause(e);
- throw error;
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class k = ForkJoinPool.class;
+ ctlOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("ctl"));
+ stealCountOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("stealCount"));
+ blockedCountOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("blockedCount"));
+ quiescerCountOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("quiescerCount"));
+ scanGuardOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("scanGuard"));
+ nextWorkerNumberOffset = UNSAFE.objectFieldOffset
+ (k.getDeclaredField("nextWorkerNumber"));
+ Class a = ForkJoinTask[].class;
+ ABASE = UNSAFE.arrayBaseOffset(a);
+ s = UNSAFE.arrayIndexScale(a);
+ } catch (Exception e) {
+ throw new Error(e);
}
+ if ((s & (s-1)) != 0)
+ throw new Error("data type scale not a power of two");
+ ASHIFT = 31 - Integer.numberOfLeadingZeros(s);
}
+
}
diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java
index b02323ffd6d..ee8ba8fcfab 100644
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinTask.java
@@ -41,7 +41,8 @@ import java.util.Collections;
import java.util.List;
import java.util.RandomAccess;
import java.util.Map;
-import java.util.WeakHashMap;
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
@@ -52,6 +53,8 @@ import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.ReentrantLock;
+import java.lang.reflect.Constructor;
/**
* Abstract base class for tasks that run within a {@link ForkJoinPool}.
@@ -95,7 +98,11 @@ import java.util.concurrent.TimeoutException;
* rethrown to callers attempting to join them. These exceptions may
* additionally include {@link RejectedExecutionException} stemming
* from internal resource exhaustion, such as failure to allocate
- * internal task queues.
+ * internal task queues. Rethrown exceptions behave in the same way as
+ * regular exceptions, but, when possible, contain stack traces (as
+ * displayed for example using {@code ex.printStackTrace()}) of both
+ * the thread that initiated the computation as well as the thread
+ * actually encountering the exception; minimally only the latter.
*
*
The primary method for awaiting completion and extracting
* results of a task is {@link #join}, but there are several variants:
@@ -192,8 +199,7 @@ public abstract class ForkJoinTask implements Future, Serializable {
* status maintenance (2) execution and awaiting completion (3)
* user-level methods that additionally report results. This is
* sometimes hard to see because this file orders exported methods
- * in a way that flows well in javadocs. In particular, most
- * join mechanics are in method quietlyJoin, below.
+ * in a way that flows well in javadocs.
*/
/*
@@ -215,91 +221,67 @@ public abstract class ForkJoinTask implements Future, Serializable {
/** The run status of this task */
volatile int status; // accessed directly by pool and workers
-
private static final int NORMAL = -1;
private static final int CANCELLED = -2;
private static final int EXCEPTIONAL = -3;
private static final int SIGNAL = 1;
- /**
- * Table of exceptions thrown by tasks, to enable reporting by
- * callers. Because exceptions are rare, we don't directly keep
- * them with task objects, but instead use a weak ref table. Note
- * that cancellation exceptions don't appear in the table, but are
- * instead recorded as status values.
- * TODO: Use ConcurrentReferenceHashMap
- */
- static final Map, Throwable> exceptionMap =
- Collections.synchronizedMap
- (new WeakHashMap, Throwable>());
-
- // Maintaining completion status
-
/**
* Marks completion and wakes up threads waiting to join this task,
* also clearing signal request bits.
*
* @param completion one of NORMAL, CANCELLED, EXCEPTIONAL
+ * @return completion status on exit
*/
- private void setCompletion(int completion) {
- int s;
- while ((s = status) >= 0) {
+ private int setCompletion(int completion) {
+ for (int s;;) {
+ if ((s = status) < 0)
+ return s;
if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) {
if (s != 0)
synchronized (this) { notifyAll(); }
- break;
+ return completion;
}
}
}
/**
- * Records exception and sets exceptional completion.
+ * Tries to block a worker thread until completed or timed out.
+ * Uses Object.wait time argument conventions.
+ * May fail on contention or interrupt.
*
- * @return status on exit
+ * @param millis if > 0, wait time.
*/
- private void setExceptionalCompletion(Throwable rex) {
- exceptionMap.put(this, rex);
- setCompletion(EXCEPTIONAL);
- }
-
- /**
- * Blocks a worker thread until completed or timed out. Called
- * only by pool.
- */
- final void internalAwaitDone(long millis, int nanos) {
- int s = status;
- if ((s == 0 &&
- UNSAFE.compareAndSwapInt(this, statusOffset, 0, SIGNAL)) ||
- s > 0) {
- try { // the odd construction reduces lock bias effects
+ final void tryAwaitDone(long millis) {
+ int s;
+ try {
+ if (((s = status) > 0 ||
+ (s == 0 &&
+ UNSAFE.compareAndSwapInt(this, statusOffset, 0, SIGNAL))) &&
+ status > 0) {
synchronized (this) {
if (status > 0)
- wait(millis, nanos);
- else
- notifyAll();
+ wait(millis);
}
- } catch (InterruptedException ie) {
- cancelIfTerminating();
}
+ } catch (InterruptedException ie) {
+ // caller must check termination
}
}
/**
* Blocks a non-worker-thread until completion.
+ * @return status upon completion
*/
- private void externalAwaitDone() {
- if (status >= 0) {
+ private int externalAwaitDone() {
+ int s;
+ if ((s = status) >= 0) {
boolean interrupted = false;
synchronized (this) {
- for (;;) {
- int s = status;
+ while ((s = status) >= 0) {
if (s == 0)
UNSAFE.compareAndSwapInt(this, statusOffset,
0, SIGNAL);
- else if (s < 0) {
- notifyAll();
- break;
- }
else {
try {
wait();
@@ -312,53 +294,308 @@ public abstract class ForkJoinTask implements Future, Serializable {
if (interrupted)
Thread.currentThread().interrupt();
}
+ return s;
}
/**
* Blocks a non-worker-thread until completion or interruption or timeout.
*/
- private void externalInterruptibleAwaitDone(boolean timed, long nanos)
+ private int externalInterruptibleAwaitDone(long millis)
throws InterruptedException {
+ int s;
if (Thread.interrupted())
throw new InterruptedException();
- if (status >= 0) {
- long startTime = timed ? System.nanoTime() : 0L;
+ if ((s = status) >= 0) {
synchronized (this) {
- for (;;) {
- long nt;
- int s = status;
+ while ((s = status) >= 0) {
if (s == 0)
UNSAFE.compareAndSwapInt(this, statusOffset,
0, SIGNAL);
- else if (s < 0) {
- notifyAll();
+ else {
+ wait(millis);
+ if (millis > 0L)
+ break;
+ }
+ }
+ }
+ }
+ return s;
+ }
+
+ /**
+ * Primary execution method for stolen tasks. Unless done, calls
+ * exec and records status if completed, but doesn't wait for
+ * completion otherwise.
+ */
+ final void doExec() {
+ if (status >= 0) {
+ boolean completed;
+ try {
+ completed = exec();
+ } catch (Throwable rex) {
+ setExceptionalCompletion(rex);
+ return;
+ }
+ if (completed)
+ setCompletion(NORMAL); // must be outside try block
+ }
+ }
+
+ /**
+ * Primary mechanics for join, get, quietlyJoin.
+ * @return status upon completion
+ */
+ private int doJoin() {
+ Thread t; ForkJoinWorkerThread w; int s; boolean completed;
+ if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+ if ((s = status) < 0)
+ return s;
+ if ((w = (ForkJoinWorkerThread)t).unpushTask(this)) {
+ try {
+ completed = exec();
+ } catch (Throwable rex) {
+ return setExceptionalCompletion(rex);
+ }
+ if (completed)
+ return setCompletion(NORMAL);
+ }
+ return w.joinTask(this);
+ }
+ else
+ return externalAwaitDone();
+ }
+
+ /**
+ * Primary mechanics for invoke, quietlyInvoke.
+ * @return status upon completion
+ */
+ private int doInvoke() {
+ int s; boolean completed;
+ if ((s = status) < 0)
+ return s;
+ try {
+ completed = exec();
+ } catch (Throwable rex) {
+ return setExceptionalCompletion(rex);
+ }
+ if (completed)
+ return setCompletion(NORMAL);
+ else
+ return doJoin();
+ }
+
+ // Exception table support
+
+ /**
+ * Table of exceptions thrown by tasks, to enable reporting by
+ * callers. Because exceptions are rare, we don't directly keep
+ * them with task objects, but instead use a weak ref table. Note
+ * that cancellation exceptions don't appear in the table, but are
+ * instead recorded as status values.
+ *
+ * Note: These statics are initialized below in static block.
+ */
+ private static final ExceptionNode[] exceptionTable;
+ private static final ReentrantLock exceptionTableLock;
+ private static final ReferenceQueue exceptionTableRefQueue;
+
+ /**
+ * Fixed capacity for exceptionTable.
+ */
+ private static final int EXCEPTION_MAP_CAPACITY = 32;
+
+ /**
+ * Key-value nodes for exception table. The chained hash table
+ * uses identity comparisons, full locking, and weak references
+ * for keys. The table has a fixed capacity because it only
+ * maintains task exceptions long enough for joiners to access
+ * them, so should never become very large for sustained
+ * periods. However, since we do not know when the last joiner
+ * completes, we must use weak references and expunge them. We do
+ * so on each operation (hence full locking). Also, some thread in
+ * any ForkJoinPool will call helpExpungeStaleExceptions when its
+ * pool becomes isQuiescent.
+ */
+ static final class ExceptionNode extends WeakReference>{
+ final Throwable ex;
+ ExceptionNode next;
+ final long thrower; // use id not ref to avoid weak cycles
+ ExceptionNode(ForkJoinTask> task, Throwable ex, ExceptionNode next) {
+ super(task, exceptionTableRefQueue);
+ this.ex = ex;
+ this.next = next;
+ this.thrower = Thread.currentThread().getId();
+ }
+ }
+
+ /**
+ * Records exception and sets exceptional completion.
+ *
+ * @return status on exit
+ */
+ private int setExceptionalCompletion(Throwable ex) {
+ int h = System.identityHashCode(this);
+ final ReentrantLock lock = exceptionTableLock;
+ lock.lock();
+ try {
+ expungeStaleExceptions();
+ ExceptionNode[] t = exceptionTable;
+ int i = h & (t.length - 1);
+ for (ExceptionNode e = t[i]; ; e = e.next) {
+ if (e == null) {
+ t[i] = new ExceptionNode(this, ex, t[i]);
+ break;
+ }
+ if (e.get() == this) // already present
+ break;
+ }
+ } finally {
+ lock.unlock();
+ }
+ return setCompletion(EXCEPTIONAL);
+ }
+
+ /**
+ * Removes exception node and clears status
+ */
+ private void clearExceptionalCompletion() {
+ int h = System.identityHashCode(this);
+ final ReentrantLock lock = exceptionTableLock;
+ lock.lock();
+ try {
+ ExceptionNode[] t = exceptionTable;
+ int i = h & (t.length - 1);
+ ExceptionNode e = t[i];
+ ExceptionNode pred = null;
+ while (e != null) {
+ ExceptionNode next = e.next;
+ if (e.get() == this) {
+ if (pred == null)
+ t[i] = next;
+ else
+ pred.next = next;
+ break;
+ }
+ pred = e;
+ e = next;
+ }
+ expungeStaleExceptions();
+ status = 0;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns a rethrowable exception for the given task, if
+ * available. To provide accurate stack traces, if the exception
+ * was not thrown by the current thread, we try to create a new
+ * exception of the same type as the one thrown, but with the
+ * recorded exception as its cause. If there is no such
+ * constructor, we instead try to use a no-arg constructor,
+ * followed by initCause, to the same effect. If none of these
+ * apply, or any fail due to other exceptions, we return the
+ * recorded exception, which is still correct, although it may
+ * contain a misleading stack trace.
+ *
+ * @return the exception, or null if none
+ */
+ private Throwable getThrowableException() {
+ if (status != EXCEPTIONAL)
+ return null;
+ int h = System.identityHashCode(this);
+ ExceptionNode e;
+ final ReentrantLock lock = exceptionTableLock;
+ lock.lock();
+ try {
+ expungeStaleExceptions();
+ ExceptionNode[] t = exceptionTable;
+ e = t[h & (t.length - 1)];
+ while (e != null && e.get() != this)
+ e = e.next;
+ } finally {
+ lock.unlock();
+ }
+ Throwable ex;
+ if (e == null || (ex = e.ex) == null)
+ return null;
+ if (e.thrower != Thread.currentThread().getId()) {
+ Class ec = ex.getClass();
+ try {
+ Constructor> noArgCtor = null;
+ Constructor>[] cs = ec.getConstructors();// public ctors only
+ for (int i = 0; i < cs.length; ++i) {
+ Constructor> c = cs[i];
+ Class>[] ps = c.getParameterTypes();
+ if (ps.length == 0)
+ noArgCtor = c;
+ else if (ps.length == 1 && ps[0] == Throwable.class)
+ return (Throwable)(c.newInstance(ex));
+ }
+ if (noArgCtor != null) {
+ Throwable wx = (Throwable)(noArgCtor.newInstance());
+ wx.initCause(ex);
+ return wx;
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ return ex;
+ }
+
+ /**
+ * Poll stale refs and remove them. Call only while holding lock.
+ */
+ private static void expungeStaleExceptions() {
+ for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
+ if (x instanceof ExceptionNode) {
+ ForkJoinTask> key = ((ExceptionNode)x).get();
+ ExceptionNode[] t = exceptionTable;
+ int i = System.identityHashCode(key) & (t.length - 1);
+ ExceptionNode e = t[i];
+ ExceptionNode pred = null;
+ while (e != null) {
+ ExceptionNode next = e.next;
+ if (e == x) {
+ if (pred == null)
+ t[i] = next;
+ else
+ pred.next = next;
break;
}
- else if (!timed)
- wait();
- else if ((nt = nanos - (System.nanoTime()-startTime)) > 0L)
- wait(nt / 1000000, (int)(nt % 1000000));
- else
- break;
+ pred = e;
+ e = next;
}
}
}
}
/**
- * Unless done, calls exec and records status if completed, but
- * doesn't wait for completion otherwise. Primary execution method
- * for ForkJoinWorkerThread.
+ * If lock is available, poll stale refs and remove them.
+ * Called from ForkJoinPool when pools become quiescent.
*/
- final void quietlyExec() {
- try {
- if (status < 0 || !exec())
- return;
- } catch (Throwable rex) {
- setExceptionalCompletion(rex);
- return;
+ static final void helpExpungeStaleExceptions() {
+ final ReentrantLock lock = exceptionTableLock;
+ if (lock.tryLock()) {
+ try {
+ expungeStaleExceptions();
+ } finally {
+ lock.unlock();
+ }
}
- setCompletion(NORMAL); // must be outside try block
+ }
+
+ /**
+ * Report the result of invoke or join; called only upon
+ * non-normal return of internal versions.
+ */
+ private V reportResult() {
+ int s; Throwable ex;
+ if ((s = status) == CANCELLED)
+ throw new CancellationException();
+ if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
+ UNSAFE.throwException(ex);
+ return getRawResult();
}
// public methods
@@ -399,11 +636,10 @@ public abstract class ForkJoinTask implements Future, Serializable {
* @return the computed result
*/
public final V join() {
- quietlyJoin();
- Throwable ex;
- if (status < NORMAL && (ex = getException()) != null)
- UNSAFE.throwException(ex);
- return getRawResult();
+ if (doJoin() != NORMAL)
+ return reportResult();
+ else
+ return getRawResult();
}
/**
@@ -415,11 +651,10 @@ public abstract class ForkJoinTask implements Future, Serializable {
* @return the computed result
*/
public final V invoke() {
- quietlyInvoke();
- Throwable ex;
- if (status < NORMAL && (ex = getException()) != null)
- UNSAFE.throwException(ex);
- return getRawResult();
+ if (doInvoke() != NORMAL)
+ return reportResult();
+ else
+ return getRawResult();
}
/**
@@ -483,22 +718,16 @@ public abstract class ForkJoinTask implements Future, Serializable {
}
else if (i != 0)
t.fork();
- else {
- t.quietlyInvoke();
- if (ex == null && t.status < NORMAL)
- ex = t.getException();
- }
+ else if (t.doInvoke() < NORMAL && ex == null)
+ ex = t.getException();
}
for (int i = 1; i <= last; ++i) {
ForkJoinTask> t = tasks[i];
if (t != null) {
if (ex != null)
t.cancel(false);
- else {
- t.quietlyJoin();
- if (ex == null && t.status < NORMAL)
- ex = t.getException();
- }
+ else if (t.doJoin() < NORMAL && ex == null)
+ ex = t.getException();
}
}
if (ex != null)
@@ -546,22 +775,16 @@ public abstract class ForkJoinTask implements Future, Serializable {
}
else if (i != 0)
t.fork();
- else {
- t.quietlyInvoke();
- if (ex == null && t.status < NORMAL)
- ex = t.getException();
- }
+ else if (t.doInvoke() < NORMAL && ex == null)
+ ex = t.getException();
}
for (int i = 1; i <= last; ++i) {
ForkJoinTask> t = ts.get(i);
if (t != null) {
if (ex != null)
t.cancel(false);
- else {
- t.quietlyJoin();
- if (ex == null && t.status < NORMAL)
- ex = t.getException();
- }
+ else if (t.doJoin() < NORMAL && ex == null)
+ ex = t.getException();
}
}
if (ex != null)
@@ -597,8 +820,7 @@ public abstract class ForkJoinTask implements Future, Serializable {
* @return {@code true} if this task is now cancelled
*/
public boolean cancel(boolean mayInterruptIfRunning) {
- setCompletion(CANCELLED);
- return status == CANCELLED;
+ return setCompletion(CANCELLED) == CANCELLED;
}
/**
@@ -614,21 +836,6 @@ public abstract class ForkJoinTask implements Future, Serializable {
}
}
- /**
- * Cancels if current thread is a terminating worker thread,
- * ignoring any exceptions thrown by cancel.
- */
- final void cancelIfTerminating() {
- Thread t = Thread.currentThread();
- if ((t instanceof ForkJoinWorkerThread) &&
- ((ForkJoinWorkerThread) t).isTerminating()) {
- try {
- cancel(false);
- } catch (Throwable ignore) {
- }
- }
- }
-
public final boolean isDone() {
return status < 0;
}
@@ -668,7 +875,7 @@ public abstract class ForkJoinTask implements Future, Serializable {
int s = status;
return ((s >= NORMAL) ? null :
(s == CANCELLED) ? new CancellationException() :
- exceptionMap.get(this));
+ getThrowableException());
}
/**
@@ -726,19 +933,13 @@ public abstract class ForkJoinTask implements Future, Serializable {
* member of a ForkJoinPool and was interrupted while waiting
*/
public final V get() throws InterruptedException, ExecutionException {
- Thread t = Thread.currentThread();
- if (t instanceof ForkJoinWorkerThread)
- quietlyJoin();
- else
- externalInterruptibleAwaitDone(false, 0L);
- int s = status;
- if (s != NORMAL) {
- Throwable ex;
- if (s == CANCELLED)
- throw new CancellationException();
- if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
- throw new ExecutionException(ex);
- }
+ int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
+ doJoin() : externalInterruptibleAwaitDone(0L);
+ Throwable ex;
+ if (s == CANCELLED)
+ throw new CancellationException();
+ if (s == EXCEPTIONAL && (ex = getThrowableException()) != null)
+ throw new ExecutionException(ex);
return getRawResult();
}
@@ -758,20 +959,39 @@ public abstract class ForkJoinTask implements Future, Serializable {
*/
public final V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
- long nanos = unit.toNanos(timeout);
Thread t = Thread.currentThread();
- if (t instanceof ForkJoinWorkerThread)
- ((ForkJoinWorkerThread)t).joinTask(this, true, nanos);
- else
- externalInterruptibleAwaitDone(true, nanos);
+ if (t instanceof ForkJoinWorkerThread) {
+ ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
+ long nanos = unit.toNanos(timeout);
+ if (status >= 0) {
+ boolean completed = false;
+ if (w.unpushTask(this)) {
+ try {
+ completed = exec();
+ } catch (Throwable rex) {
+ setExceptionalCompletion(rex);
+ }
+ }
+ if (completed)
+ setCompletion(NORMAL);
+ else if (status >= 0 && nanos > 0)
+ w.pool.timedAwaitJoin(this, nanos);
+ }
+ }
+ else {
+ long millis = unit.toMillis(timeout);
+ if (millis > 0)
+ externalInterruptibleAwaitDone(millis);
+ }
int s = status;
if (s != NORMAL) {
Throwable ex;
if (s == CANCELLED)
throw new CancellationException();
- if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
+ if (s != EXCEPTIONAL)
+ throw new TimeoutException();
+ if ((ex = getThrowableException()) != null)
throw new ExecutionException(ex);
- throw new TimeoutException();
}
return getRawResult();
}
@@ -783,28 +1003,7 @@ public abstract class ForkJoinTask implements Future, Serializable {
* known to have aborted.
*/
public final void quietlyJoin() {
- Thread t;
- if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
- ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
- if (status >= 0) {
- if (w.unpushTask(this)) {
- boolean completed;
- try {
- completed = exec();
- } catch (Throwable rex) {
- setExceptionalCompletion(rex);
- return;
- }
- if (completed) {
- setCompletion(NORMAL);
- return;
- }
- }
- w.joinTask(this, false, 0L);
- }
- }
- else
- externalAwaitDone();
+ doJoin();
}
/**
@@ -813,19 +1012,7 @@ public abstract class ForkJoinTask implements Future, Serializable {
* exception.
*/
public final void quietlyInvoke() {
- if (status >= 0) {
- boolean completed;
- try {
- completed = exec();
- } catch (Throwable rex) {
- setExceptionalCompletion(rex);
- return;
- }
- if (completed)
- setCompletion(NORMAL);
- else
- quietlyJoin();
- }
+ doInvoke();
}
/**
@@ -864,8 +1051,9 @@ public abstract class ForkJoinTask implements Future, Serializable {
*/
public void reinitialize() {
if (status == EXCEPTIONAL)
- exceptionMap.remove(this);
- status = 0;
+ clearExceptionalCompletion();
+ else
+ status = 0;
}
/**
@@ -1176,23 +1364,23 @@ public abstract class ForkJoinTask implements Future, Serializable {
s.defaultReadObject();
Object ex = s.readObject();
if (ex != null)
- setExceptionalCompletion((Throwable) ex);
+ setExceptionalCompletion((Throwable)ex);
}
// Unsafe mechanics
-
- private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
- private static final long statusOffset =
- objectFieldOffset("status", ForkJoinTask.class);
-
- private static long objectFieldOffset(String field, Class> klazz) {
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long statusOffset;
+ static {
+ exceptionTableLock = new ReentrantLock();
+ exceptionTableRefQueue = new ReferenceQueue();
+ exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
try {
- return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
- } catch (NoSuchFieldException e) {
- // Convert Exception to corresponding Error
- NoSuchFieldError error = new NoSuchFieldError(field);
- error.initCause(e);
- throw error;
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ statusOffset = UNSAFE.objectFieldOffset
+ (ForkJoinTask.class.getDeclaredField("status"));
+ } catch (Exception e) {
+ throw new Error(e);
}
}
+
}
diff --git a/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java b/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java
index 7d79c5190e2..2f48080a664 100644
--- a/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java
+++ b/jdk/src/share/classes/java/util/concurrent/ForkJoinWorkerThread.java
@@ -35,9 +35,7 @@
package java.util.concurrent;
-import java.util.Random;
import java.util.Collection;
-import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.RejectedExecutionException;
/**
@@ -84,33 +82,38 @@ public class ForkJoinWorkerThread extends Thread {
* a footprint as possible even in programs generating huge
* numbers of tasks. To accomplish this, we shift the CAS
* arbitrating pop vs deq (steal) from being on the indices
- * ("base" and "sp") to the slots themselves (mainly via method
- * "casSlotNull()"). So, both a successful pop and deq 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 sp.
- * 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 sp == 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
- * deq have not fully committed. Note that this means that the deq
- * 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
+ * ("queueBase" and "queueTop") to the slots themselves (mainly
+ * via method "casSlotNull()"). So, both a successful pop and deq
+ * 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
+ * queueBase or queueTop. 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 queueTop == queueBase means the queue is empty,
+ * but otherwise may err on the side of possibly making the queue
+ * appear nonempty when a push, pop, or deq have not fully
+ * committed. Note that this means that the deq 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 deq or new push on
- * any empty queue to complete. One reason this works well here is
- * that apparently-nonempty often means soon-to-be-stealable,
- * which gives threads a chance to set activation status if
- * necessary before stealing.
+ * any empty queue to complete.
*
* This approach also enables support for "async mode" where local
* task processing is in FIFO, not LIFO order; simply by using a
* version of deq rather than pop when locallyFifo is true (as set
* by the ForkJoinPool). This allows use in message-passing
- * frameworks in which tasks are never joined.
+ * 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.)
*
* When a worker would otherwise be blocked waiting to join a
* task, it first tries a form of linear helping: Each worker
@@ -137,29 +140,26 @@ public class ForkJoinWorkerThread extends Thread {
* 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_DEPTH) and fall back to suspending the worker and if
- * necessary replacing it with a spare (see
- * ForkJoinPool.awaitJoin).
+ * MAX_HELP) and fall back to suspending the worker and if
+ * necessary replacing it with another.
*
* Efficient implementation of these algorithms currently relies
* on an uncomfortable amount of "Unsafe" mechanics. To maintain
- * correct orderings, reads and writes of variable base require
- * volatile ordering. Variable sp does not require volatile
- * writes but still needs store-ordering, which we accomplish by
- * pre-incrementing sp before filling the slot with an ordered
- * store. (Pre-incrementing also enables backouts used in
- * joinTask.) Because they are protected by volatile base reads,
- * reads of the queue array and its slots by other threads do not
- * need volatile load semantics, but writes (in push) require
- * store order and CASes (in pop and deq) require (volatile) CAS
- * semantics. (Michael, Saraswat, and Vechev's algorithm has
- * similar properties, but without support for nulling slots.)
- * Since these combinations aren't supported using ordinary
- * volatiles, the only way to accomplish these efficiently is to
- * use direct Unsafe calls. (Using external AtomicIntegers and
- * AtomicReferenceArrays for the indices and array is
- * significantly slower because of memory locality and indirection
- * effects.)
+ * correct orderings, reads and writes of variable queueBase
+ * require volatile ordering. Variable queueTop need not be
+ * volatile because non-local reads always follow those of
+ * queueBase. Similarly, because they are protected by volatile
+ * queueBase reads, reads of the queue array and its slots by
+ * other threads do not need volatile load semantics, but writes
+ * (in push) require store order and CASes (in pop and deq)
+ * require (volatile) CAS semantics. (Michael, Saraswat, and
+ * Vechev's algorithm has similar properties, but without support
+ * for nulling slots.) Since these combinations aren't supported
+ * using ordinary volatiles, the only way to accomplish these
+ * efficiently is to use direct Unsafe calls. (Using external
+ * AtomicIntegers and AtomicReferenceArrays for the indices and
+ * array is significantly slower because of memory locality and
+ * indirection effects.)
*
* Further, performance on most platforms is very sensitive to
* placement and sizing of the (resizable) queue array. Even
@@ -167,30 +167,13 @@ public class ForkJoinWorkerThread extends Thread {
* initial size must be large enough to counteract cache
* contention effects across multiple queues (especially in the
* presence of GC cardmarking). Also, to improve thread-locality,
- * queues are initialized after starting. All together, these
- * low-level implementation choices produce as much as a factor of
- * 4 performance improvement compared to naive implementations,
- * and enable the processing of billions of tasks per second,
- * sometimes at the expense of ugliness.
+ * queues are initialized after starting.
*/
/**
- * Generator for initial random seeds for random victim
- * selection. This is used only to create initial seeds. Random
- * steals use a cheaper xorshift generator per steal attempt. We
- * expect only rare contention on seedGenerator, so just use a
- * plain Random.
+ * Mask for pool indices encoded as shorts
*/
- private static final Random seedGenerator = new Random();
-
- /**
- * The maximum stolen->joining link depth allowed in helpJoinTask.
- * Depths for legitimate chains are unbounded, but we use a fixed
- * constant to avoid (otherwise unchecked) cycles and bound
- * staleness of traversal parameters at the expense of sometimes
- * blocking when we could be helping.
- */
- private static final int MAX_HELP_DEPTH = 8;
+ private static final int SMASK = 0xffff;
/**
* Capacity of work-stealing queue array upon initialization.
@@ -200,12 +183,19 @@ public class ForkJoinWorkerThread extends Thread {
private static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
/**
- * Maximum work-stealing queue array size. Must be less than or
- * equal to 1 << (31 - width of array entry) to ensure lack of
- * index wraparound. The value is set in the static block
- * at the end of this file after obtaining width.
+ * Maximum size for queue array. Must be a power of two
+ * less than or equal to 1 << (31 - width of array entry) to
+ * ensure lack of index wraparound, but is capped at a lower
+ * value to help users trap runaway computations.
*/
- private static final int MAXIMUM_QUEUE_CAPACITY;
+ private static final int MAXIMUM_QUEUE_CAPACITY = 1 << 24; // 16M
+
+ /**
+ * The work-stealing queue array. Size must be a power of two.
+ * Initialized when started (as oposed to when constructed), to
+ * improve memory locality.
+ */
+ ForkJoinTask>[] queue;
/**
* The pool this thread works in. Accessed directly by ForkJoinTask.
@@ -213,25 +203,19 @@ public class ForkJoinWorkerThread extends Thread {
final ForkJoinPool pool;
/**
- * The work-stealing queue array. Size must be a power of two.
- * Initialized in onStart, to improve memory locality.
+ * Index (mod queue.length) of next queue slot to push to or pop
+ * from. It is written only by owner thread, and accessed by other
+ * threads only after reading (volatile) queueBase. Both queueTop
+ * and queueBase are allowed to wrap around on overflow, but
+ * (queueTop - queueBase) still estimates size.
*/
- private ForkJoinTask>[] queue;
+ int queueTop;
/**
* Index (mod queue.length) of least valid queue slot, which is
* always the next position to steal from if nonempty.
*/
- private volatile int base;
-
- /**
- * Index (mod queue.length) of next queue slot to push to or pop
- * from. It is written only by owner thread, and accessed by other
- * threads only after reading (volatile) base. Both sp and base
- * are allowed to wrap around on overflow, but (sp - base) still
- * estimates size.
- */
- private int sp;
+ volatile int queueBase;
/**
* The index of most recent stealer, used as a hint to avoid
@@ -240,92 +224,68 @@ public class ForkJoinWorkerThread extends Thread {
* of them (usually the most current). Declared non-volatile,
* relying on other prevailing sync to keep reasonably current.
*/
- private int stealHint;
-
- /**
- * Run state of this worker. In addition to the usual run levels,
- * tracks if this worker is suspended as a spare, and if it was
- * killed (trimmed) while suspended. However, "active" status is
- * maintained separately and modified only in conjunction with
- * CASes of the pool's runState (which are currently sadly
- * manually inlined for performance.) Accessed directly by pool
- * to simplify checks for normal (zero) status.
- */
- volatile int runState;
-
- private static final int TERMINATING = 0x01;
- private static final int TERMINATED = 0x02;
- private static final int SUSPENDED = 0x04; // inactive spare
- private static final int TRIMMED = 0x08; // killed while suspended
-
- /**
- * Number of steals. Directly accessed (and reset) by
- * pool.tryAccumulateStealCount when idle.
- */
- int stealCount;
-
- /**
- * Seed for random number generator for choosing steal victims.
- * Uses Marsaglia xorshift. Must be initialized as nonzero.
- */
- private int seed;
-
- /**
- * Activity status. When true, this worker is considered active.
- * Accessed directly by pool. Must be false upon construction.
- */
- boolean active;
-
- /**
- * True if use local fifo, not default lifo, for local polling.
- * Shadows value from ForkJoinPool.
- */
- private final boolean locallyFifo;
+ int stealHint;
/**
* Index of this worker in pool array. Set once by pool before
* running, and accessed directly by pool to locate this worker in
* its workers array.
*/
- int poolIndex;
+ final int poolIndex;
/**
- * The last pool event waited for. Accessed only by pool in
- * callback methods invoked within this thread.
+ * Encoded record for pool task waits. Usages are always
+ * surrounded by volatile reads/writes
*/
- int lastEventCount;
+ int nextWait;
/**
- * Encoded index and event count of next event waiter. Accessed
- * only by ForkJoinPool for managing event waiters.
+ * Complement of poolIndex, offset by count of entries of task
+ * waits. Accessed by ForkJoinPool to manage event waiters.
*/
- volatile long nextWaiter;
+ volatile int eventCount;
/**
- * Number of times this thread suspended as spare. Accessed only
- * by pool.
+ * Seed for random number generator for choosing steal victims.
+ * Uses Marsaglia xorshift. Must be initialized as nonzero.
*/
- int spareCount;
+ int seed;
/**
- * Encoded index and count of next spare waiter. Accessed only
- * by ForkJoinPool for managing spares.
+ * Number of steals. Directly accessed (and reset) by pool when
+ * idle.
*/
- volatile int nextSpare;
+ int stealCount;
/**
- * The task currently being joined, set only when actively trying
- * to help other stealers in helpJoinTask. Written only by this
- * thread, but read by others.
+ * True if this worker should or did terminate
*/
- private volatile ForkJoinTask> currentJoin;
+ volatile boolean terminate;
+
+ /**
+ * Set to true before LockSupport.park; false on return
+ */
+ volatile boolean parked;
+
+ /**
+ * True if use local fifo, not default lifo, for local polling.
+ * Shadows value from ForkJoinPool.
+ */
+ final boolean locallyFifo;
/**
* The task most recently stolen from another worker (or
- * submission queue). Written only by this thread, but read by
- * others.
+ * submission queue). All uses are surrounded by enough volatile
+ * reads/writes to maintain as non-volatile.
*/
- private volatile ForkJoinTask> currentSteal;
+ ForkJoinTask> currentSteal;
+
+ /**
+ * The task currently being joined, set only when actively trying
+ * to help other stealers in helpJoinTask. All uses are surrounded
+ * by enough volatile reads/writes to maintain as non-volatile.
+ */
+ ForkJoinTask> currentJoin;
/**
* Creates a ForkJoinWorkerThread operating in the given pool.
@@ -334,24 +294,19 @@ public class ForkJoinWorkerThread extends Thread {
* @throws NullPointerException if pool is null
*/
protected ForkJoinWorkerThread(ForkJoinPool pool) {
+ super(pool.nextWorkerName());
this.pool = pool;
- this.locallyFifo = pool.locallyFifo;
- setDaemon(true);
- // To avoid exposing construction details to subclasses,
- // remaining initialization is in start() and onStart()
- }
-
- /**
- * Performs additional initialization and starts this thread.
- */
- final void start(int poolIndex, UncaughtExceptionHandler ueh) {
- this.poolIndex = poolIndex;
+ int k = pool.registerWorker(this);
+ poolIndex = k;
+ eventCount = ~k & SMASK; // clear wait count
+ locallyFifo = pool.locallyFifo;
+ Thread.UncaughtExceptionHandler ueh = pool.ueh;
if (ueh != null)
setUncaughtExceptionHandler(ueh);
- start();
+ setDaemon(true);
}
- // Public/protected methods
+ // Public methods
/**
* Returns the pool hosting this thread.
@@ -375,6 +330,25 @@ public class ForkJoinWorkerThread extends Thread {
return poolIndex;
}
+ // Randomization
+
+ /**
+ * Computes next value for random victim probes and backoffs.
+ * Scans don't require a very high quality generator, but also not
+ * a crummy one. Marsaglia xor-shift is cheap and works well
+ * enough. Note: This is manually inlined in FJP.scan() to avoid
+ * writes inside busy loops.
+ */
+ private int nextSeed() {
+ int r = seed;
+ r ^= r << 13;
+ r ^= r >>> 17;
+ r ^= r << 5;
+ return seed = r;
+ }
+
+ // Run State management
+
/**
* Initializes internal state after construction but before
* processing any tasks. If you override this method, you must
@@ -385,15 +359,9 @@ public class ForkJoinWorkerThread extends Thread {
* processing tasks.
*/
protected void onStart() {
- int rs = seedGenerator.nextInt();
- seed = (rs == 0) ? 1 : rs; // seed must be nonzero
-
- // Allocate name string and arrays in this thread
- String pid = Integer.toString(pool.getPoolNumber());
- String wid = Integer.toString(poolIndex);
- setName("ForkJoinPool-" + pid + "-worker-" + wid);
-
queue = new ForkJoinTask>[INITIAL_QUEUE_CAPACITY];
+ int r = pool.workerSeedGenerator.nextInt();
+ seed = (r == 0)? 1 : r; // must be nonzero
}
/**
@@ -406,16 +374,9 @@ public class ForkJoinWorkerThread extends Thread {
*/
protected void onTermination(Throwable exception) {
try {
- ForkJoinPool p = pool;
- if (active) {
- int a; // inline p.tryDecrementActiveCount
- active = false;
- do {} while (!UNSAFE.compareAndSwapInt
- (p, poolRunStateOffset, a = p.runState, a - 1));
- }
+ terminate = true;
cancelTasks();
- setTerminated();
- p.workerTerminated(this);
+ pool.deregisterWorker(this, exception);
} catch (Throwable ex) { // Shouldn't ever happen
if (exception == null) // but if so, at least rethrown
exception = ex;
@@ -434,7 +395,7 @@ public class ForkJoinWorkerThread extends Thread {
Throwable exception = null;
try {
onStart();
- mainLoop();
+ pool.work(this);
} catch (Throwable ex) {
exception = ex;
} finally {
@@ -442,81 +403,6 @@ public class ForkJoinWorkerThread extends Thread {
}
}
- // helpers for run()
-
- /**
- * Finds and executes tasks, and checks status while running.
- */
- private void mainLoop() {
- boolean ran = false; // true if ran a task on last step
- ForkJoinPool p = pool;
- for (;;) {
- p.preStep(this, ran);
- if (runState != 0)
- break;
- ran = tryExecSteal() || tryExecSubmission();
- }
- }
-
- /**
- * Tries to steal a task and execute it.
- *
- * @return true if ran a task
- */
- private boolean tryExecSteal() {
- ForkJoinTask> t;
- if ((t = scan()) != null) {
- t.quietlyExec();
- UNSAFE.putOrderedObject(this, currentStealOffset, null);
- if (sp != base)
- execLocalTasks();
- return true;
- }
- return false;
- }
-
- /**
- * If a submission exists, try to activate and run it.
- *
- * @return true if ran a task
- */
- private boolean tryExecSubmission() {
- ForkJoinPool p = pool;
- // This loop is needed in case attempt to activate fails, in
- // which case we only retry if there still appears to be a
- // submission.
- while (p.hasQueuedSubmissions()) {
- ForkJoinTask> t; int a;
- if (active || // inline p.tryIncrementActiveCount
- (active = UNSAFE.compareAndSwapInt(p, poolRunStateOffset,
- a = p.runState, a + 1))) {
- if ((t = p.pollSubmission()) != null) {
- UNSAFE.putOrderedObject(this, currentStealOffset, t);
- t.quietlyExec();
- UNSAFE.putOrderedObject(this, currentStealOffset, null);
- if (sp != base)
- execLocalTasks();
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Runs local tasks until queue is empty or shut down. Call only
- * while active.
- */
- private void execLocalTasks() {
- while (runState == 0) {
- ForkJoinTask> t = locallyFifo ? locallyDeqTask() : popTask();
- if (t != null)
- t.quietlyExec();
- else if (sp == base)
- break;
- }
- }
-
/*
* Intrinsics-based atomic writes for queue slots. These are
* basically the same as methods in AtomicReferenceArray, but
@@ -528,10 +414,20 @@ public class ForkJoinWorkerThread extends Thread {
* because they are protected by other volatile reads and are
* confirmed by CASes.
*
- * Most uses don't actually call these methods, but instead contain
- * inlined forms that enable more predictable optimization. We
- * don't define the version of write used in pushTask at all, but
- * instead inline there a store-fenced array slot write.
+ * Most uses don't actually call these methods, but instead
+ * contain inlined forms that enable more predictable
+ * optimization. We don't define the version of write used in
+ * pushTask at all, but instead inline there a store-fenced array
+ * slot write.
+ *
+ * Also in most methods, as a performance (not correctness) issue,
+ * we'd like to encourage compilers not to arbitrarily postpone
+ * setting queueTop after writing slot. Currently there is no
+ * intrinsic for arranging this, but using Unsafe putOrderedInt
+ * may be a preferable strategy on some compilers even though its
+ * main effect is a pre-, not post- fence. To simplify possible
+ * changes, the option is left in comments next to the associated
+ * assignments.
*/
/**
@@ -540,7 +436,7 @@ public class ForkJoinWorkerThread extends Thread {
*/
private static final boolean casSlotNull(ForkJoinTask>[] q, int i,
ForkJoinTask> t) {
- return UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase, t, null);
+ return UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE, t, null);
}
/**
@@ -550,7 +446,7 @@ public class ForkJoinWorkerThread extends Thread {
*/
private static final void writeSlot(ForkJoinTask>[] q, int i,
ForkJoinTask> t) {
- UNSAFE.putObjectVolatile(q, (i << qShift) + qBase, t);
+ UNSAFE.putObjectVolatile(q, (i << ASHIFT) + ABASE, t);
}
// queue methods
@@ -561,14 +457,43 @@ public class ForkJoinWorkerThread extends Thread {
* @param t the task. Caller must ensure non-null.
*/
final void pushTask(ForkJoinTask> t) {
- ForkJoinTask>[] q = queue;
- int mask = q.length - 1; // implicit assert q != null
- int s = sp++; // ok to increment sp before slot write
- UNSAFE.putOrderedObject(q, ((s & mask) << qShift) + qBase, t);
- if ((s -= base) == 0)
- pool.signalWork(); // was empty
- else if (s == mask)
- growQueue(); // is full
+ ForkJoinTask>[] q; int s, m;
+ if ((q = queue) != null) { // ignore if queue removed
+ long u = (((s = queueTop) & (m = q.length - 1)) << ASHIFT) + ABASE;
+ UNSAFE.putOrderedObject(q, u, t);
+ queueTop = s + 1; // or use putOrderedInt
+ if ((s -= queueBase) <= 2)
+ pool.signalWork();
+ else if (s == m)
+ growQueue();
+ }
+ }
+
+ /**
+ * Creates or doubles queue array. Transfers elements by
+ * emulating steals (deqs) from old array and placing, oldest
+ * first, into new array.
+ */
+ private void growQueue() {
+ ForkJoinTask>[] oldQ = queue;
+ int size = oldQ != null ? oldQ.length << 1 : INITIAL_QUEUE_CAPACITY;
+ if (size > MAXIMUM_QUEUE_CAPACITY)
+ throw new RejectedExecutionException("Queue capacity exceeded");
+ if (size < INITIAL_QUEUE_CAPACITY)
+ size = INITIAL_QUEUE_CAPACITY;
+ ForkJoinTask>[] q = queue = new ForkJoinTask>[size];
+ int mask = size - 1;
+ int top = queueTop;
+ int oldMask;
+ if (oldQ != null && (oldMask = oldQ.length - 1) >= 0) {
+ for (int b = queueBase; b != top; ++b) {
+ long u = ((b & oldMask) << ASHIFT) + ABASE;
+ Object x = UNSAFE.getObjectVolatile(oldQ, u);
+ if (x != null && UNSAFE.compareAndSwapObject(oldQ, u, x, null))
+ UNSAFE.putObjectVolatile
+ (q, ((b & mask) << ASHIFT) + ABASE, x);
+ }
+ }
}
/**
@@ -579,35 +504,34 @@ public class ForkJoinWorkerThread extends Thread {
* @return a task, or null if none or contended
*/
final ForkJoinTask> deqTask() {
- ForkJoinTask> t;
- ForkJoinTask>[] q;
- int b, i;
- if (sp != (b = base) &&
+ ForkJoinTask> t; ForkJoinTask>[] q; int b, i;
+ if (queueTop != (b = queueBase) &&
(q = queue) != null && // must read q after b
- (t = q[i = (q.length - 1) & b]) != null && base == b &&
- UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase, t, null)) {
- base = b + 1;
+ (i = (q.length - 1) & b) >= 0 &&
+ (t = q[i]) != null && queueBase == b &&
+ UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE, t, null)) {
+ queueBase = b + 1;
return t;
}
return null;
}
/**
- * Tries to take a task from the base of own queue. Assumes active
- * status. Called only by this thread.
+ * Tries to take a task from the base of own queue. Called only
+ * by this thread.
*
* @return a task, or null if none
*/
final ForkJoinTask> locallyDeqTask() {
+ ForkJoinTask> t; int m, b, i;
ForkJoinTask>[] q = queue;
- if (q != null) {
- ForkJoinTask> t;
- int b, i;
- while (sp != (b = base)) {
- if ((t = q[i = (q.length - 1) & b]) != null && base == b &&
- UNSAFE.compareAndSwapObject(q, (i << qShift) + qBase,
+ if (q != null && (m = q.length - 1) >= 0) {
+ while (queueTop != (b = queueBase)) {
+ if ((t = q[i = m & b]) != null &&
+ queueBase == b &&
+ UNSAFE.compareAndSwapObject(q, (i << ASHIFT) + ABASE,
t, null)) {
- base = b + 1;
+ queueBase = b + 1;
return t;
}
}
@@ -616,35 +540,21 @@ public class ForkJoinWorkerThread extends Thread {
}
/**
- * Returns a popped task, or null if empty. Assumes active status.
+ * Returns a popped task, or null if empty.
* Called only by this thread.
*/
private ForkJoinTask> popTask() {
+ int m;
ForkJoinTask>[] q = queue;
- if (q != null) {
- int s;
- while ((s = sp) != base) {
- int i = (q.length - 1) & --s;
- long u = (i << qShift) + qBase; // raw offset
+ if (q != null && (m = q.length - 1) >= 0) {
+ for (int s; (s = queueTop) != queueBase;) {
+ int i = m & --s;
+ long u = (i << ASHIFT) + ABASE; // raw offset
ForkJoinTask> t = q[i];
if (t == null) // lost to stealer
break;
if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
- /*
- * Note: here and in related methods, as a
- * performance (not correctness) issue, we'd like
- * to encourage compiler not to arbitrarily
- * postpone setting sp after successful CAS.
- * Currently there is no intrinsic for arranging
- * this, but using Unsafe putOrderedInt may be a
- * preferable strategy on some compilers even
- * though its main effect is a pre-, not post-
- * fence. To simplify possible changes, the option
- * is left in comments next to the associated
- * assignments.
- */
- sp = s; // putOrderedInt may encourage more timely write
- // UNSAFE.putOrderedInt(this, spOffset, s);
+ queueTop = s; // or putOrderedInt
return t;
}
}
@@ -654,18 +564,17 @@ public class ForkJoinWorkerThread extends Thread {
/**
* Specialized version of popTask to pop only if topmost element
- * is the given task. Called only by this thread while active.
+ * is the given task. Called only by this thread.
*
* @param t the task. Caller must ensure non-null.
*/
final boolean unpushTask(ForkJoinTask> t) {
+ ForkJoinTask>[] q;
int s;
- ForkJoinTask>[] q = queue;
- if ((s = sp) != base && q != null &&
+ if ((q = queue) != null && (s = queueTop) != queueBase &&
UNSAFE.compareAndSwapObject
- (q, (((q.length - 1) & --s) << qShift) + qBase, t, null)) {
- sp = s; // putOrderedInt may encourage more timely write
- // UNSAFE.putOrderedInt(this, spOffset, s);
+ (q, (((q.length - 1) & --s) << ASHIFT) + ABASE, t, null)) {
+ queueTop = s; // or putOrderedInt
return true;
}
return false;
@@ -675,222 +584,30 @@ public class ForkJoinWorkerThread extends Thread {
* Returns next task, or null if empty or contended.
*/
final ForkJoinTask> peekTask() {
+ int m;
ForkJoinTask>[] q = queue;
- if (q == null)
+ if (q == null || (m = q.length - 1) < 0)
return null;
- int mask = q.length - 1;
- int i = locallyFifo ? base : (sp - 1);
- return q[i & mask];
+ int i = locallyFifo ? queueBase : (queueTop - 1);
+ return q[i & m];
}
+ // Support methods for ForkJoinPool
+
/**
- * Doubles queue array size. Transfers elements by emulating
- * steals (deqs) from old array and placing, oldest first, into
- * new array.
+ * Runs the given task, plus any local tasks until queue is empty
*/
- private void growQueue() {
- ForkJoinTask>[] oldQ = queue;
- int oldSize = oldQ.length;
- int newSize = oldSize << 1;
- if (newSize > MAXIMUM_QUEUE_CAPACITY)
- throw new RejectedExecutionException("Queue capacity exceeded");
- ForkJoinTask>[] newQ = queue = new ForkJoinTask>[newSize];
-
- int b = base;
- int bf = b + oldSize;
- int oldMask = oldSize - 1;
- int newMask = newSize - 1;
- do {
- int oldIndex = b & oldMask;
- ForkJoinTask> t = oldQ[oldIndex];
- if (t != null && !casSlotNull(oldQ, oldIndex, t))
- t = null;
- writeSlot(newQ, b & newMask, t);
- } while (++b != bf);
- pool.signalWork();
- }
-
- /**
- * Computes next value for random victim probe in scan(). Scans
- * don't require a very high quality generator, but also not a
- * crummy one. Marsaglia xor-shift is cheap and works well enough.
- * Note: This is manually inlined in scan().
- */
- private static final int xorShift(int r) {
- r ^= r << 13;
- r ^= r >>> 17;
- return r ^ (r << 5);
- }
-
- /**
- * Tries to steal a task from another worker. Starts at a random
- * index of workers array, and probes workers until finding one
- * with non-empty queue or finding that all are empty. It
- * randomly selects the first n probes. If these are empty, it
- * resorts to a circular sweep, which is necessary to accurately
- * set active status. (The circular sweep uses steps of
- * approximately half the array size plus 1, to avoid bias
- * stemming from leftmost packing of the array in ForkJoinPool.)
- *
- * This method must be both fast and quiet -- usually avoiding
- * memory accesses that could disrupt cache sharing etc other than
- * those needed to check for and take tasks (or to activate if not
- * already active). This accounts for, among other things,
- * updating random seed in place without storing it until exit.
- *
- * @return a task, or null if none found
- */
- private ForkJoinTask> scan() {
- ForkJoinPool p = pool;
- ForkJoinWorkerThread[] ws; // worker array
- int n; // upper bound of #workers
- if ((ws = p.workers) != null && (n = ws.length) > 1) {
- boolean canSteal = active; // shadow active status
- int r = seed; // extract seed once
- int mask = n - 1;
- int j = -n; // loop counter
- int k = r; // worker index, random if j < 0
- for (;;) {
- ForkJoinWorkerThread v = ws[k & mask];
- r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // inline xorshift
- ForkJoinTask>[] q; ForkJoinTask> t; int b, a;
- if (v != null && (b = v.base) != v.sp &&
- (q = v.queue) != null) {
- int i = (q.length - 1) & b;
- long u = (i << qShift) + qBase; // raw offset
- int pid = poolIndex;
- if ((t = q[i]) != null) {
- if (!canSteal && // inline p.tryIncrementActiveCount
- UNSAFE.compareAndSwapInt(p, poolRunStateOffset,
- a = p.runState, a + 1))
- canSteal = active = true;
- if (canSteal && v.base == b++ &&
- UNSAFE.compareAndSwapObject(q, u, t, null)) {
- v.base = b;
- v.stealHint = pid;
- UNSAFE.putOrderedObject(this,
- currentStealOffset, t);
- seed = r;
- ++stealCount;
- return t;
- }
- }
- j = -n;
- k = r; // restart on contention
- }
- else if (++j <= 0)
- k = r;
- else if (j <= n)
- k += (n >>> 1) | 1;
- else
- break;
- }
- }
- return null;
- }
-
- // Run State management
-
- // status check methods used mainly by ForkJoinPool
- final boolean isRunning() { return runState == 0; }
- final boolean isTerminated() { return (runState & TERMINATED) != 0; }
- final boolean isSuspended() { return (runState & SUSPENDED) != 0; }
- final boolean isTrimmed() { return (runState & TRIMMED) != 0; }
-
- final boolean isTerminating() {
- if ((runState & TERMINATING) != 0)
- return true;
- if (pool.isAtLeastTerminating()) { // propagate pool state
- shutdown();
- return true;
- }
- return false;
- }
-
- /**
- * Sets state to TERMINATING. Does NOT unpark or interrupt
- * to wake up if currently blocked. Callers must do so if desired.
- */
- final void shutdown() {
+ final void execTask(ForkJoinTask> t) {
+ currentSteal = t;
for (;;) {
- int s = runState;
- if ((s & (TERMINATING|TERMINATED)) != 0)
- break;
- if ((s & SUSPENDED) != 0) { // kill and wakeup if suspended
- if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
- (s & ~SUSPENDED) |
- (TRIMMED|TERMINATING)))
- break;
- }
- else if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
- s | TERMINATING))
+ if (t != null)
+ t.doExec();
+ if (queueTop == queueBase)
break;
+ t = locallyFifo ? locallyDeqTask() : popTask();
}
- }
-
- /**
- * Sets state to TERMINATED. Called only by onTermination().
- */
- private void setTerminated() {
- int s;
- do {} while (!UNSAFE.compareAndSwapInt(this, runStateOffset,
- s = runState,
- s | (TERMINATING|TERMINATED)));
- }
-
- /**
- * If suspended, tries to set status to unsuspended.
- * Does NOT wake up if blocked.
- *
- * @return true if successful
- */
- final boolean tryUnsuspend() {
- int s;
- while (((s = runState) & SUSPENDED) != 0) {
- if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
- s & ~SUSPENDED))
- return true;
- }
- return false;
- }
-
- /**
- * Sets suspended status and blocks as spare until resumed
- * or shutdown.
- */
- final void suspendAsSpare() {
- for (;;) { // set suspended unless terminating
- int s = runState;
- if ((s & TERMINATING) != 0) { // must kill
- if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
- s | (TRIMMED | TERMINATING)))
- return;
- }
- else if (UNSAFE.compareAndSwapInt(this, runStateOffset, s,
- s | SUSPENDED))
- break;
- }
- ForkJoinPool p = pool;
- p.pushSpare(this);
- while ((runState & SUSPENDED) != 0) {
- if (p.tryAccumulateStealCount(this)) {
- interrupted(); // clear/ignore interrupts
- if ((runState & SUSPENDED) == 0)
- break;
- LockSupport.park(this);
- }
- }
- }
-
- // Misc support methods for ForkJoinPool
-
- /**
- * Returns an estimate of the number of tasks in the queue. Also
- * used by ForkJoinTask.
- */
- final int getQueueSize() {
- int n; // external calls must read base first
- return (n = -base + sp) <= 0 ? 0 : n;
+ ++stealCount;
+ currentSteal = null;
}
/**
@@ -899,17 +616,12 @@ public class ForkJoinWorkerThread extends Thread {
*/
final void cancelTasks() {
ForkJoinTask> cj = currentJoin; // try to cancel ongoing tasks
- if (cj != null && cj.status >= 0) {
+ if (cj != null && cj.status >= 0)
cj.cancelIgnoringExceptions();
- try {
- this.interrupt(); // awaken wait
- } catch (SecurityException ignore) {
- }
- }
ForkJoinTask> cs = currentSteal;
if (cs != null && cs.status >= 0)
cs.cancelIgnoringExceptions();
- while (base != sp) {
+ while (queueBase != queueTop) {
ForkJoinTask> t = deqTask();
if (t != null)
t.cancelIgnoringExceptions();
@@ -923,7 +635,7 @@ public class ForkJoinWorkerThread extends Thread {
*/
final int drainTasksTo(Collection super ForkJoinTask>> c) {
int n = 0;
- while (base != sp) {
+ while (queueBase != queueTop) {
ForkJoinTask> t = deqTask();
if (t != null) {
c.add(t);
@@ -935,21 +647,20 @@ public class ForkJoinWorkerThread extends Thread {
// Support methods for ForkJoinTask
+ /**
+ * Returns an estimate of the number of tasks in the queue.
+ */
+ final int getQueueSize() {
+ return queueTop - queueBase;
+ }
+
/**
* Gets and removes a local task.
*
* @return a task, if available
*/
final ForkJoinTask> pollLocalTask() {
- ForkJoinPool p = pool;
- while (sp != base) {
- int a; // inline p.tryIncrementActiveCount
- if (active ||
- (active = UNSAFE.compareAndSwapInt(p, poolRunStateOffset,
- a = p.runState, a + 1)))
- return locallyFifo ? locallyDeqTask() : popTask();
- }
- return null;
+ return locallyFifo ? locallyDeqTask() : popTask();
}
/**
@@ -958,172 +669,205 @@ public class ForkJoinWorkerThread extends Thread {
* @return a task, if available
*/
final ForkJoinTask> pollTask() {
+ ForkJoinWorkerThread[] ws;
ForkJoinTask> t = pollLocalTask();
- if (t == null) {
- t = scan();
- // cannot retain/track/help steal
- UNSAFE.putOrderedObject(this, currentStealOffset, null);
+ if (t != null || (ws = pool.workers) == null)
+ return t;
+ int n = ws.length; // cheap version of FJP.scan
+ int steps = n << 1;
+ int r = nextSeed();
+ int i = 0;
+ while (i < steps) {
+ ForkJoinWorkerThread w = ws[(i++ + r) & (n - 1)];
+ if (w != null && w.queueBase != w.queueTop && w.queue != null) {
+ if ((t = w.deqTask()) != null)
+ return t;
+ i = 0;
+ }
}
- return t;
+ return null;
}
/**
- * Possibly runs some tasks and/or blocks, until task is done.
+ * The maximum stolen->joining link depth allowed in helpJoinTask,
+ * as well as the maximum number of retries (allowing on average
+ * one staleness retry per level) per attempt to instead try
+ * compensation. Depths for legitimate chains are unbounded, but
+ * we use a fixed constant to avoid (otherwise unchecked) cycles
+ * and bound staleness of traversal parameters at the expense of
+ * sometimes blocking when we could be helping.
+ */
+ private static final int MAX_HELP = 16;
+
+ /**
+ * Possibly runs some tasks and/or blocks, until joinMe is done.
*
* @param joinMe the task to join
- * @param timed true if use timed wait
- * @param nanos wait time if timed
+ * @return completion status on exit
*/
- final void joinTask(ForkJoinTask> joinMe, boolean timed, long nanos) {
- // currentJoin only written by this thread; only need ordered store
+ final int joinTask(ForkJoinTask> joinMe) {
ForkJoinTask> prevJoin = currentJoin;
- UNSAFE.putOrderedObject(this, currentJoinOffset, joinMe);
- pool.awaitJoin(joinMe, this, timed, nanos);
- UNSAFE.putOrderedObject(this, currentJoinOffset, prevJoin);
+ currentJoin = joinMe;
+ for (int s, retries = MAX_HELP;;) {
+ if ((s = joinMe.status) < 0) {
+ currentJoin = prevJoin;
+ return s;
+ }
+ if (retries > 0) {
+ if (queueTop != queueBase) {
+ if (!localHelpJoinTask(joinMe))
+ retries = 0; // cannot help
+ }
+ else if (retries == MAX_HELP >>> 1) {
+ --retries; // check uncommon case
+ if (tryDeqAndExec(joinMe) >= 0)
+ Thread.yield(); // for politeness
+ }
+ else
+ retries = helpJoinTask(joinMe)? MAX_HELP : retries - 1;
+ }
+ else {
+ retries = MAX_HELP; // restart if not done
+ pool.tryAwaitJoin(joinMe);
+ }
+ }
}
/**
- * Tries to locate and help perform tasks for a stealer of the
- * given task, or in turn one of its stealers. Traces
+ * If present, pops and executes the given task, or any other
+ * cancelled task
+ *
+ * @return false if any other non-cancelled task exists in local queue
+ */
+ private boolean localHelpJoinTask(ForkJoinTask> joinMe) {
+ int s, i; ForkJoinTask>[] q; ForkJoinTask> t;
+ if ((s = queueTop) != queueBase && (q = queue) != null &&
+ (i = (q.length - 1) & --s) >= 0 &&
+ (t = q[i]) != null) {
+ if (t != joinMe && t.status >= 0)
+ return false;
+ if (UNSAFE.compareAndSwapObject
+ (q, (i << ASHIFT) + ABASE, t, null)) {
+ queueTop = s; // or putOrderedInt
+ t.doExec();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tries to locate and execute tasks for a stealer of the given
+ * task, or in turn one of its stealers, Traces
* currentSteal->currentJoin links looking for a thread working on
* a descendant of the given task and with a non-empty queue to
- * steal back and execute tasks from.
- *
- * The implementation is very branchy to cope with potential
- * inconsistencies or loops encountering chains that are stale,
- * unknown, or of length greater than MAX_HELP_DEPTH links. All
- * of these cases are dealt with by just returning back to the
- * caller, who is expected to retry if other join mechanisms also
- * don't work out.
+ * steal back and execute tasks from. The implementation is very
+ * branchy to cope with potential inconsistencies or loops
+ * encountering chains that are stale, unknown, or of length
+ * greater than MAX_HELP links. All of these cases are dealt with
+ * by just retrying by caller.
*
* @param joinMe the task to join
- * @param running if false, then must update pool count upon
- * running a task
- * @return value of running on exit
+ * @param canSteal true if local queue is empty
+ * @return true if ran a task
*/
- final boolean helpJoinTask(ForkJoinTask> joinMe, boolean running) {
- /*
- * Initial checks to (1) abort if terminating; (2) clean out
- * old cancelled tasks from local queue; (3) if joinMe is next
- * task, run it; (4) omit scan if local queue nonempty (since
- * it may contain non-descendents of joinMe).
- */
- ForkJoinPool p = pool;
- for (;;) {
- ForkJoinTask>[] q;
- int s;
- if (joinMe.status < 0)
- return running;
- else if ((runState & TERMINATING) != 0) {
- joinMe.cancelIgnoringExceptions();
- return running;
- }
- else if ((s = sp) == base || (q = queue) == null)
- break; // queue empty
- else {
- int i = (q.length - 1) & --s;
- long u = (i << qShift) + qBase; // raw offset
- ForkJoinTask> t = q[i];
- if (t == null)
- break; // lost to a stealer
- else if (t != joinMe && t.status >= 0)
- return running; // cannot safely help
- else if ((running ||
- (running = p.tryIncrementRunningCount())) &&
- UNSAFE.compareAndSwapObject(q, u, t, null)) {
- sp = s; // putOrderedInt may encourage more timely write
- // UNSAFE.putOrderedInt(this, spOffset, s);
- t.quietlyExec();
- }
- }
- }
-
- int n; // worker array size
- ForkJoinWorkerThread[] ws = p.workers;
- if (ws != null && (n = ws.length) > 1) { // need at least 2 workers
- ForkJoinTask> task = joinMe; // base of chain
- ForkJoinWorkerThread thread = this; // thread with stolen task
-
- outer:for (int d = 0; d < MAX_HELP_DEPTH; ++d) { // chain length
+ private boolean helpJoinTask(ForkJoinTask> joinMe) {
+ boolean helped = false;
+ int m = pool.scanGuard & SMASK;
+ ForkJoinWorkerThread[] ws = pool.workers;
+ if (ws != null && ws.length > m && joinMe.status >= 0) {
+ int levels = MAX_HELP; // remaining chain length
+ ForkJoinTask> task = joinMe; // base of chain
+ outer:for (ForkJoinWorkerThread thread = this;;) {
// Try to find v, the stealer of task, by first using hint
- ForkJoinWorkerThread v = ws[thread.stealHint & (n - 1)];
+ ForkJoinWorkerThread v = ws[thread.stealHint & m];
if (v == null || v.currentSteal != task) {
- for (int j = 0; ; ++j) { // search array
- if (j < n) {
- ForkJoinTask> vs;
- if ((v = ws[j]) != null &&
- (vs = v.currentSteal) != null) {
- if (joinMe.status < 0)
- break outer;
- if (vs == task) {
- if (task.status < 0)
- break outer; // stale
- thread.stealHint = j;
- break; // save hint for next time
- }
- }
+ for (int j = 0; ;) { // search array
+ if ((v = ws[j]) != null && v.currentSteal == task) {
+ thread.stealHint = j;
+ break; // save hint for next time
}
- else
- break outer; // no stealer
+ if (++j > m)
+ break outer; // can't find stealer
}
}
-
// Try to help v, using specialized form of deqTask
for (;;) {
+ ForkJoinTask>[] q; int b, i;
if (joinMe.status < 0)
break outer;
- int b = v.base;
- ForkJoinTask>[] q = v.queue;
- if (b == v.sp || q == null)
- break; // empty
- int i = (q.length - 1) & b;
- long u = (i << qShift) + qBase;
+ if ((b = v.queueBase) == v.queueTop ||
+ (q = v.queue) == null ||
+ (i = (q.length-1) & b) < 0)
+ break; // empty
+ long u = (i << ASHIFT) + ABASE;
ForkJoinTask> t = q[i];
if (task.status < 0)
- break outer; // stale
- if (t != null &&
- (running ||
- (running = p.tryIncrementRunningCount())) &&
- v.base == b++ &&
+ break outer; // stale
+ if (t != null && v.queueBase == b &&
UNSAFE.compareAndSwapObject(q, u, t, null)) {
- if (t != joinMe && joinMe.status < 0) {
- UNSAFE.putObjectVolatile(q, u, t);
- break outer; // joinMe cancelled; back out
- }
- v.base = b;
- if (t.status >= 0) {
- ForkJoinTask> ps = currentSteal;
- int pid = poolIndex;
- v.stealHint = pid;
- UNSAFE.putOrderedObject(this,
- currentStealOffset, t);
- t.quietlyExec();
- UNSAFE.putOrderedObject(this,
- currentStealOffset, ps);
- }
- }
- else if ((runState & TERMINATING) != 0) {
- joinMe.cancelIgnoringExceptions();
- break outer;
+ v.queueBase = b + 1;
+ v.stealHint = poolIndex;
+ ForkJoinTask> ps = currentSteal;
+ currentSteal = t;
+ t.doExec();
+ currentSteal = ps;
+ helped = true;
}
}
-
// Try to descend to find v's stealer
ForkJoinTask> next = v.currentJoin;
- if (task.status < 0 || next == null || next == task ||
- joinMe.status < 0)
- break; // done, stale, dead-end, or cyclic
- task = next;
- thread = v;
+ if (--levels > 0 && task.status >= 0 &&
+ next != null && next != task) {
+ task = next;
+ thread = v;
+ }
+ else
+ break; // max levels, stale, dead-end, or cyclic
}
}
- return running;
+ return helped;
}
/**
- * Implements ForkJoinTask.getSurplusQueuedTaskCount().
- * Returns an estimate of the number of tasks, offset by a
- * function of number of idle workers.
+ * Performs an uncommon case for joinTask: If task t is at base of
+ * some workers queue, steals and executes it.
+ *
+ * @param t the task
+ * @return t's status
+ */
+ private int tryDeqAndExec(ForkJoinTask> t) {
+ int m = pool.scanGuard & SMASK;
+ ForkJoinWorkerThread[] ws = pool.workers;
+ if (ws != null && ws.length > m && t.status >= 0) {
+ for (int j = 0; j <= m; ++j) {
+ ForkJoinTask>[] q; int b, i;
+ ForkJoinWorkerThread v = ws[j];
+ if (v != null &&
+ (b = v.queueBase) != v.queueTop &&
+ (q = v.queue) != null &&
+ (i = (q.length - 1) & b) >= 0 &&
+ q[i] == t) {
+ long u = (i << ASHIFT) + ABASE;
+ if (v.queueBase == b &&
+ UNSAFE.compareAndSwapObject(q, u, t, null)) {
+ v.queueBase = b + 1;
+ v.stealHint = poolIndex;
+ ForkJoinTask> ps = currentSteal;
+ currentSteal = t;
+ t.doExec();
+ currentSteal = ps;
+ }
+ break;
+ }
+ }
+ }
+ return t.status;
+ }
+
+ /**
+ * Implements ForkJoinTask.getSurplusQueuedTaskCount(). Returns
+ * an estimate of the number of tasks, offset by a function of
+ * number of idle workers.
*
* This method provides a cheap heuristic guide for task
* partitioning when programmers, frameworks, tools, or languages
@@ -1159,82 +903,96 @@ public class ForkJoinWorkerThread extends Thread {
* When all threads are active, it is on average OK to estimate
* surplus strictly locally. In steady-state, if one thread is
* maintaining say 2 surplus tasks, then so are others. So we can
- * just use estimated queue length (although note that (sp - base)
- * can be an overestimate because of stealers lagging increments
- * of base). However, this strategy alone leads to serious
- * mis-estimates in some non-steady-state conditions (ramp-up,
- * ramp-down, other stalls). We can detect many of these by
- * further considering the number of "idle" threads, that are
+ * just use estimated queue length (although note that (queueTop -
+ * queueBase) can be an overestimate because of stealers lagging
+ * increments of queueBase). However, this strategy alone leads
+ * to serious mis-estimates in some non-steady-state conditions
+ * (ramp-up, ramp-down, other stalls). We can detect 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.
*/
final int getEstimatedSurplusTaskCount() {
- return sp - base - pool.idlePerActive();
+ return queueTop - queueBase - pool.idlePerActive();
}
/**
- * Runs tasks until {@code pool.isQuiescent()}.
+ * Runs tasks until {@code pool.isQuiescent()}. We piggyback on
+ * pool's active count ctl maintenance, but rather than blocking
+ * when tasks cannot be found, we rescan until all others cannot
+ * find tasks either. The bracketing by pool quiescerCounts
+ * updates suppresses pool auto-shutdown mechanics that could
+ * otherwise prematurely terminate the pool because all threads
+ * appear to be inactive.
*/
final void helpQuiescePool() {
+ boolean active = true;
ForkJoinTask> ps = currentSteal; // to restore below
+ ForkJoinPool p = pool;
+ p.addQuiescerCount(1);
for (;;) {
- ForkJoinTask> t = pollLocalTask();
- if (t != null || (t = scan()) != null)
- t.quietlyExec();
+ ForkJoinWorkerThread[] ws = p.workers;
+ ForkJoinWorkerThread v = null;
+ int n;
+ if (queueTop != queueBase)
+ v = this;
+ else if (ws != null && (n = ws.length) > 1) {
+ ForkJoinWorkerThread w;
+ int r = nextSeed(); // cheap version of FJP.scan
+ int steps = n << 1;
+ for (int i = 0; i < steps; ++i) {
+ if ((w = ws[(i + r) & (n - 1)]) != null &&
+ w.queueBase != w.queueTop) {
+ v = w;
+ break;
+ }
+ }
+ }
+ if (v != null) {
+ ForkJoinTask> t;
+ if (!active) {
+ active = true;
+ p.addActiveCount(1);
+ }
+ if ((t = (v != this) ? v.deqTask() :
+ locallyFifo? locallyDeqTask() : popTask()) != null) {
+ currentSteal = t;
+ t.doExec();
+ currentSteal = ps;
+ }
+ }
else {
- ForkJoinPool p = pool;
- int a; // to inline CASes
if (active) {
- if (!UNSAFE.compareAndSwapInt
- (p, poolRunStateOffset, a = p.runState, a - 1))
- continue; // retry later
- active = false; // inactivate
- UNSAFE.putOrderedObject(this, currentStealOffset, ps);
+ active = false;
+ p.addActiveCount(-1);
}
if (p.isQuiescent()) {
- active = true; // re-activate
- do {} while (!UNSAFE.compareAndSwapInt
- (p, poolRunStateOffset, a = p.runState, a+1));
- return;
+ p.addActiveCount(1);
+ p.addQuiescerCount(-1);
+ break;
}
}
}
}
// Unsafe mechanics
-
- private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
- private static final long spOffset =
- objectFieldOffset("sp", ForkJoinWorkerThread.class);
- private static final long runStateOffset =
- objectFieldOffset("runState", ForkJoinWorkerThread.class);
- private static final long currentJoinOffset =
- objectFieldOffset("currentJoin", ForkJoinWorkerThread.class);
- private static final long currentStealOffset =
- objectFieldOffset("currentSteal", ForkJoinWorkerThread.class);
- private static final long qBase =
- UNSAFE.arrayBaseOffset(ForkJoinTask[].class);
- private static final long poolRunStateOffset = // to inline CAS
- objectFieldOffset("runState", ForkJoinPool.class);
-
- private static final int qShift;
+ private static final sun.misc.Unsafe UNSAFE;
+ private static final long ABASE;
+ private static final int ASHIFT;
static {
- int s = UNSAFE.arrayIndexScale(ForkJoinTask[].class);
+ int s;
+ try {
+ UNSAFE = sun.misc.Unsafe.getUnsafe();
+ Class a = ForkJoinTask[].class;
+ ABASE = UNSAFE.arrayBaseOffset(a);
+ s = UNSAFE.arrayIndexScale(a);
+ } catch (Exception e) {
+ throw new Error(e);
+ }
if ((s & (s-1)) != 0)
throw new Error("data type scale not a power of two");
- qShift = 31 - Integer.numberOfLeadingZeros(s);
- MAXIMUM_QUEUE_CAPACITY = 1 << (31 - qShift);
+ ASHIFT = 31 - Integer.numberOfLeadingZeros(s);
}
- private static long objectFieldOffset(String field, Class> klazz) {
- try {
- return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
- } catch (NoSuchFieldException e) {
- // Convert Exception to corresponding Error
- NoSuchFieldError error = new NoSuchFieldError(field);
- error.initCause(e);
- throw error;
- }
- }
}
diff --git a/jdk/src/share/classes/javax/swing/JOptionPane.java b/jdk/src/share/classes/javax/swing/JOptionPane.java
index 66154cf39b5..307d834b4e6 100644
--- a/jdk/src/share/classes/javax/swing/JOptionPane.java
+++ b/jdk/src/share/classes/javax/swing/JOptionPane.java
@@ -987,11 +987,33 @@ public class JOptionPane extends JComponent implements Accessible
}
dialog.pack();
dialog.setLocationRelativeTo(parentComponent);
+
+ final PropertyChangeListener listener = new PropertyChangeListener() {
+ public void propertyChange(PropertyChangeEvent event) {
+ // Let the defaultCloseOperation handle the closing
+ // if the user closed the window without selecting a button
+ // (newValue = null in that case). Otherwise, close the dialog.
+ if (dialog.isVisible() && event.getSource() == JOptionPane.this &&
+ (event.getPropertyName().equals(VALUE_PROPERTY) ||
+ event.getPropertyName().equals(INPUT_VALUE_PROPERTY)) &&
+ event.getNewValue() != null &&
+ event.getNewValue() != JOptionPane.UNINITIALIZED_VALUE) {
+ dialog.setVisible(false);
+ }
+ }
+ };
+
WindowAdapter adapter = new WindowAdapter() {
private boolean gotFocus = false;
public void windowClosing(WindowEvent we) {
setValue(null);
}
+
+ public void windowClosed(WindowEvent e) {
+ removePropertyChangeListener(listener);
+ dialog.getContentPane().removeAll();
+ }
+
public void windowGainedFocus(WindowEvent we) {
// Once window gets focus, set initial focus
if (!gotFocus) {
@@ -1008,20 +1030,8 @@ public class JOptionPane extends JComponent implements Accessible
setValue(JOptionPane.UNINITIALIZED_VALUE);
}
});
- addPropertyChangeListener(new PropertyChangeListener() {
- public void propertyChange(PropertyChangeEvent event) {
- // Let the defaultCloseOperation handle the closing
- // if the user closed the window without selecting a button
- // (newValue = null in that case). Otherwise, close the dialog.
- if (dialog.isVisible() && event.getSource() == JOptionPane.this &&
- (event.getPropertyName().equals(VALUE_PROPERTY) ||
- event.getPropertyName().equals(INPUT_VALUE_PROPERTY)) &&
- event.getNewValue() != null &&
- event.getNewValue() != JOptionPane.UNINITIALIZED_VALUE) {
- dialog.setVisible(false);
- }
- }
- });
+
+ addPropertyChangeListener(listener);
}
diff --git a/jdk/src/share/classes/javax/swing/Timer.java b/jdk/src/share/classes/javax/swing/Timer.java
index 9e98d5f920e..c6c80baeda9 100644
--- a/jdk/src/share/classes/javax/swing/Timer.java
+++ b/jdk/src/share/classes/javax/swing/Timer.java
@@ -35,6 +35,10 @@ import java.util.concurrent.locks.*;
import java.awt.*;
import java.awt.event.*;
import java.io.Serializable;
+import java.io.*;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import javax.swing.event.EventListenerList;
@@ -208,6 +212,22 @@ public class Timer implements Serializable
}
}
+ /*
+ * The timer's AccessControlContext.
+ */
+ private transient volatile AccessControlContext acc =
+ AccessController.getContext();
+
+ /**
+ * Returns the acc this timer was constructed with.
+ */
+ final AccessControlContext getAccessControlContext() {
+ if (acc == null) {
+ throw new SecurityException(
+ "Timer is missing AccessControlContext");
+ }
+ return acc;
+ }
/**
* DoPostEvent is a runnable class that fires actionEvents to
@@ -587,8 +607,13 @@ public class Timer implements Serializable
void post() {
- if (notify.compareAndSet(false, true) || !coalesce) {
- SwingUtilities.invokeLater(doPostEvent);
+ if (notify.compareAndSet(false, true) || !coalesce) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Void run() {
+ SwingUtilities.invokeLater(doPostEvent);
+ return null;
+ }
+ }, getAccessControlContext());
}
}
@@ -596,6 +621,13 @@ public class Timer implements Serializable
return lock;
}
+ private void readObject(ObjectInputStream in)
+ throws ClassNotFoundException, IOException
+ {
+ this.acc = AccessController.getContext();
+ in.defaultReadObject();
+ }
+
/*
* We have to use readResolve because we can not initialize final
* fields for deserialized object otherwise
diff --git a/jdk/src/share/classes/javax/swing/TransferHandler.java b/jdk/src/share/classes/javax/swing/TransferHandler.java
index eb7f8d1a644..dd54b259eef 100644
--- a/jdk/src/share/classes/javax/swing/TransferHandler.java
+++ b/jdk/src/share/classes/javax/swing/TransferHandler.java
@@ -42,6 +42,16 @@ import sun.awt.AppContext;
import sun.swing.*;
import sun.awt.SunToolkit;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+import sun.misc.SharedSecrets;
+import sun.misc.JavaSecurityAccess;
+
+import sun.awt.AWTAccessor;
+
/**
* This class is used to handle the transfer of a Transferable
* to and from Swing components. The Transferable is used to
@@ -1686,7 +1696,37 @@ public class TransferHandler implements Serializable {
return true;
}
- public void actionPerformed(ActionEvent e) {
+ private static final JavaSecurityAccess javaSecurityAccess =
+ SharedSecrets.getJavaSecurityAccess();
+
+ public void actionPerformed(final ActionEvent e) {
+ final Object src = e.getSource();
+
+ final PrivilegedAction action = new PrivilegedAction() {
+ public Void run() {
+ actionPerformedImpl(e);
+ return null;
+ }
+ };
+
+ final AccessControlContext stack = AccessController.getContext();
+ final AccessControlContext srcAcc = AWTAccessor.getComponentAccessor().getAccessControlContext((Component)src);
+ final AccessControlContext eventAcc = AWTAccessor.getAWTEventAccessor().getAccessControlContext(e);
+
+ if (srcAcc == null) {
+ javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc);
+ } else {
+ javaSecurityAccess.doIntersectionPrivilege(
+ new PrivilegedAction() {
+ public Void run() {
+ javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);
+ return null;
+ }
+ }, stack, srcAcc);
+ }
+ }
+
+ private void actionPerformedImpl(ActionEvent e) {
Object src = e.getSource();
if (src instanceof JComponent) {
JComponent c = (JComponent) src;
diff --git a/jdk/src/share/classes/org/relaxng/datatype/Datatype.java b/jdk/src/share/classes/org/relaxng/datatype/Datatype.java
deleted file mode 100644
index f1b4d8df244..00000000000
--- a/jdk/src/share/classes/org/relaxng/datatype/Datatype.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (c) 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.
- */
-
-package org.relaxng.datatype;
-
-/**
- * Datatype object.
- *
- * This object has the following functionality:
- *
- *
- * functionality to identify a class of character sequences. This is
- * done through the isValid method.
- *
- * functionality to produce a "value object" from a character sequence and
- * context information.
- *
- * functionality to test the equality of two value objects.
- *
- *
- * This interface also defines the createStreamingValidator method,
- * which is intended to efficiently support the validation of
- * large character sequences.
- *
- * @author James Clark
- * @author Kohsuke KAWAGUCHI
- */
-public interface Datatype {
-
- /**
- * Checks if the specified 'literal' matches this Datatype
- * with respect to the current context.
- *
- * @param literal
- * the lexical representation to be checked.
- * @param context
- * If this datatype is context-dependent
- * (i.e. the {@link #isContextDependent} method returns true),
- * then the caller must provide a non-null valid context object.
- * Otherwise, the caller can pass null.
- *
- * @return
- * true if the 'literal' is a member of this Datatype;
- * false if it's not a member of this Datatype.
- */
- boolean isValid( String literal, ValidationContext context );
-
- /**
- * Similar to the isValid method but throws an exception with diagnosis
- * in case of errors.
- *
- *
- * If the specified 'literal' is a valid lexical representation for this
- * datatype, then this method must return without throwing any exception.
- * If not, the callee must throw an exception (with diagnosis message,
- * if possible.)
- *
- *
- * The application can use this method to provide detailed error message
- * to users. This method is kept separate from the isValid method to
- * achieve higher performance during normal validation.
- *
- * @exception DatatypeException
- * If the given literal is invalid, then this exception is thrown.
- * If the callee supports error diagnosis, then the exception should
- * contain a diagnosis message.
- */
- void checkValid( String literal, ValidationContext context )
- throws DatatypeException;
-
- /**
- * Creates an instance of a streaming validator for this type.
- *
- *
- * By using streaming validators instead of the isValid method,
- * the caller can avoid keeping the entire string, which is
- * sometimes quite big, in memory.
- *
- * @param context
- * If this datatype is context-dependent
- * (i.e. the {@link #isContextDependent} method returns true),
- * then the caller must provide a non-null valid context object.
- * Otherwise, the caller can pass null.
- * The callee may keep a reference to this context object
- * only while the returned streaming validator is being used.
- */
- DatatypeStreamingValidator createStreamingValidator( ValidationContext context );
-
- /**
- * Converts lexcial value and the current context to the corresponding
- * value object.
- *
- *
- * The caller cannot generally assume that the value object is
- * a meaningful Java object. For example, the caller cannot expect
- * this method to return java.lang.Number type for
- * the "integer" type of XML Schema Part 2.
- *
- *
- * Also, the caller cannot assume that the equals method and
- * the hashCode method of the value object are consistent with
- * the semantics of the datatype. For that purpose, the sameValue
- * method and the valueHashCode method have to be used. Note that
- * this means you cannot use classes like
- * java.util.Hashtable to store the value objects.
- *
- *
- * The returned value object should be used solely for the sameValue
- * and valueHashCode methods.
- *
- * @param context
- * If this datatype is context-dependent
- * (when the {@link #isContextDependent} method returns true),
- * then the caller must provide a non-null valid context object.
- * Otherwise, the caller can pass null.
- *
- * @return null
- * when the given lexical value is not a valid lexical
- * value for this type.
- */
- Object createValue( String literal, ValidationContext context );
-
- /**
- * Tests the equality of two value objects which were originally
- * created by the createValue method of this object.
- *
- * The behavior is undefined if objects not created by this type
- * are passed. It is the caller's responsibility to ensure that
- * value objects belong to this type.
- *
- * @return
- * true if two value objects are considered equal according to
- * the definition of this datatype; false if otherwise.
- */
- boolean sameValue( Object value1, Object value2 );
-
-
- /**
- * Computes the hash code for a value object,
- * which is consistent with the sameValue method.
- *
- * @return
- * hash code for the specified value object.
- */
- int valueHashCode( Object value );
-
-
-
-
- /**
- * Indicates that the datatype doesn't have ID/IDREF semantics.
- *
- * This value is one of the possible return values of the
- * {@link #getIdType} method.
- */
- public static final int ID_TYPE_NULL = 0;
-
- /**
- * Indicates that RELAX NG compatibility processors should
- * treat this datatype as having ID semantics.
- *
- * This value is one of the possible return values of the
- * {@link #getIdType} method.
- */
- public static final int ID_TYPE_ID = 1;
-
- /**
- * Indicates that RELAX NG compatibility processors should
- * treat this datatype as having IDREF semantics.
- *
- * This value is one of the possible return values of the
- * {@link #getIdType} method.
- */
- public static final int ID_TYPE_IDREF = 2;
-
- /**
- * Indicates that RELAX NG compatibility processors should
- * treat this datatype as having IDREFS semantics.
- *
- * This value is one of the possible return values of the
- * {@link #getIdType} method.
- */
- public static final int ID_TYPE_IDREFS = 3;
-
- /**
- * Checks if the ID/IDREF semantics is associated with this
- * datatype.
- *
- *
- * This method is introduced to support the RELAX NG DTD
- * compatibility spec. (Of course it's always free to use
- * this method for other purposes.)
- *
- *
- * If you are implementing a datatype library and have no idea about
- * the "RELAX NG DTD compatibility" thing, just return
- * ID_TYPE_NULL is fine.
- *
- * @return
- * If this datatype doesn't have any ID/IDREF semantics,
- * it returns {@link #ID_TYPE_NULL}. If it has such a semantics
- * (for example, XSD:ID, XSD:IDREF and comp:ID type), then
- * it returns {@link #ID_TYPE_ID}, {@link #ID_TYPE_IDREF} or
- * {@link #ID_TYPE_IDREFS}.
- */
- public int getIdType();
-
-
- /**
- * Checks if this datatype may need a context object for
- * the validation.
- *
- *
- * The callee must return true even when the context
- * is not always necessary. (For example, the "QName" type
- * doesn't need a context object when validating unprefixed
- * string. But nonetheless QName must return true.)
- *
- *
- * XSD's string and short types
- * are examples of context-independent datatypes.
- * Its QName and ENTITY types
- * are examples of context-dependent datatypes.
- *
- *
- * When a datatype is context-independent, then
- * the {@link #isValid} method, the {@link #checkValid} method,
- * the {@link #createStreamingValidator} method and
- * the {@link #createValue} method can be called without
- * providing a context object.
- *
- * @return
- * true if this datatype is context-dependent
- * (it needs a context object sometimes);
- *
- * false if this datatype is context-in dependent
- * (it never needs a context object).
- */
- public boolean isContextDependent();
-}
diff --git a/jdk/src/share/classes/org/relaxng/datatype/DatatypeBuilder.java b/jdk/src/share/classes/org/relaxng/datatype/DatatypeBuilder.java
deleted file mode 100644
index ea15f33cea2..00000000000
--- a/jdk/src/share/classes/org/relaxng/datatype/DatatypeBuilder.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 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.
- */
-
-package org.relaxng.datatype;
-
-/**
- * Creates a user-defined type by adding parameters to
- * the pre-defined type.
- *
- * @author James Clark
- * @author Kohsuke KAWAGUCHI
- */
-public interface DatatypeBuilder {
-
- /**
- * Adds a new parameter.
- *
- * @param name
- * The name of the parameter to be added.
- * @param strValue
- * The raw value of the parameter. Caller may not normalize
- * this value because any white space is potentially significant.
- * @param context
- * The context information which can be used by the callee to
- * acquire additional information. This context object is
- * valid only during this method call. The callee may not
- * keep a reference to this object.
- * @exception DatatypeException
- * When the given parameter is inappropriate for some reason.
- * The callee is responsible to recover from this error.
- * That is, the object should behave as if no such error
- * was occured.
- */
- void addParameter( String name, String strValue, ValidationContext context )
- throws DatatypeException;
-
- /**
- * Derives a new Datatype from a Datatype by parameters that
- * were already set through the addParameter method.
- *
- * @exception DatatypeException
- * DatatypeException must be thrown if the derivation is
- * somehow invalid. For example, a required parameter is missing,
- * etc. The exception should contain a diagnosis message
- * if possible.
- */
- Datatype createDatatype() throws DatatypeException;
-}
diff --git a/jdk/src/share/classes/org/relaxng/datatype/DatatypeLibrary.java b/jdk/src/share/classes/org/relaxng/datatype/DatatypeLibrary.java
deleted file mode 100644
index f3f790d91e2..00000000000
--- a/jdk/src/share/classes/org/relaxng/datatype/DatatypeLibrary.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 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.
- */
-
-package org.relaxng.datatype;
-
-/**
- * A Datatype library
- *
- * @author James Clark
- * @author Kohsuke KAWAGUCHI
- */
-public interface DatatypeLibrary {
-
- /**
- * Creates a new instance of DatatypeBuilder.
- *
- * The callee should throw a DatatypeException in case of an error.
- *
- * @param baseTypeLocalName
- * The local name of the base type.
- *
- * @return
- * A non-null valid datatype object.
- */
- DatatypeBuilder createDatatypeBuilder( String baseTypeLocalName )
- throws DatatypeException;
-
- /**
- * Gets or creates a pre-defined type.
- *
- * This is just a short-cut of
- * createDatatypeBuilder(typeLocalName).createDatatype();
- *
- * The callee should throw a DatatypeException in case of an error.
- *
- * @return
- * A non-null valid datatype object.
- */
- Datatype createDatatype( String typeLocalName ) throws DatatypeException;
-}
diff --git a/jdk/src/share/classes/org/relaxng/datatype/DatatypeLibraryFactory.java b/jdk/src/share/classes/org/relaxng/datatype/DatatypeLibraryFactory.java
deleted file mode 100644
index e406c078894..00000000000
--- a/jdk/src/share/classes/org/relaxng/datatype/DatatypeLibraryFactory.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 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.
- */
-
-package org.relaxng.datatype;
-
-/**
- * Factory class for the DatatypeLibrary class.
- *
- *
- * The datatype library should provide the implementation of
- * this interface if it wants to be found by the schema processors.
- * The implementor also have to place a file in your jar file.
- * See the reference datatype library implementation for detail.
- *
- * @author James Clark
- * @author Kohsuke KAWAGUCHI
- */
-public interface DatatypeLibraryFactory
-{
- /**
- * Creates a new instance of a DatatypeLibrary that supports
- * the specified namespace URI.
- *
- * @return
- * null if the specified namespace URI is not
- * supported.
- */
- DatatypeLibrary createDatatypeLibrary( String namespaceURI );
-}
diff --git a/jdk/src/share/classes/org/relaxng/datatype/DatatypeStreamingValidator.java b/jdk/src/share/classes/org/relaxng/datatype/DatatypeStreamingValidator.java
deleted file mode 100644
index 56663923278..00000000000
--- a/jdk/src/share/classes/org/relaxng/datatype/DatatypeStreamingValidator.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 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.
- */
-
-package org.relaxng.datatype;
-
-/**
- * Datatype streaming validator.
- *
- *
- * The streaming validator is an optional feature that is useful for
- * certain Datatypes. It allows the caller to incrementally provide
- * the literal.
- *
- * @author James Clark
- * @author Kohsuke KAWAGUCHI
- */
-public interface DatatypeStreamingValidator {
-
- /**
- * Passes an additional fragment of the literal.
- *
- *
- * The application can call this method several times, then call
- * the isValid method (or the checkValid method) to check the validity
- * of the accumulated characters.
- */
- void addCharacters( char[] buf, int start, int len );
-
- /**
- * Tells if the accumulated literal is valid with respect to
- * the underlying Datatype.
- *
- * @return
- * True if it is valid. False if otherwise.
- */
- boolean isValid();
-
- /**
- * Similar to the isValid method, but this method throws
- * Exception (with possibly diagnostic information), instead of
- * returning false.
- *
- * @exception DatatypeException
- * If the callee supports the diagnosis and the accumulated
- * literal is invalid, then this exception that possibly
- * contains diagnosis information is thrown.
- */
- void checkValid() throws DatatypeException;
-}
diff --git a/jdk/src/share/classes/org/relaxng/datatype/ValidationContext.java b/jdk/src/share/classes/org/relaxng/datatype/ValidationContext.java
deleted file mode 100644
index 8e37b0ee6a5..00000000000
--- a/jdk/src/share/classes/org/relaxng/datatype/ValidationContext.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 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.
- */
-
-package org.relaxng.datatype;
-
-/**
- * An interface that must be implemented by caller to
- * provide context information that is necessary to
- * perform validation of some Datatypes.
- *
- * @author James Clark
- * @author Kohsuke KAWAGUCHI
- */
-public interface ValidationContext {
-
- /**
- * Resolves a namespace prefix to the corresponding namespace URI.
- *
- * This method is used for validating the QName type, for example.
- *
- *
- * If the prefix is "" (empty string), it indicates
- * an unprefixed value. The callee
- * should resolve it as for an unprefixed
- * element, rather than for an unprefixed attribute.
- *
- *
- * If the prefix is "xml", then the callee must resolve
- * this prefix into "http://www.w3.org/XML/1998/namespace",
- * as defined in the XML Namespaces Recommendation.
- *
- * @return
- * namespace URI of this prefix.
- * If the specified prefix is not declared,
- * the implementation must return null.
- */
- String resolveNamespacePrefix( String prefix );
-
- /**
- * Returns the base URI of the context. The null string may be returned
- * if no base URI is known.
- */
- String getBaseUri();
-
- /**
- * Checks if an unparsed entity is declared with the
- * specified name.
- *
- * @return
- * true
- * if the DTD has an unparsed entity declaration for
- * the specified name.
- * false
- * otherwise.
- */
- boolean isUnparsedEntity( String entityName );
-
- /**
- * Checks if a notation is declared with the
- * specified name.
- *
- * @return
- * true
- * if the DTD has a notation declaration for the specified name.
- * false
- * otherwise.
- */
- boolean isNotation( String notationName );
-}
diff --git a/jdk/src/share/classes/org/relaxng/datatype/helpers/DatatypeLibraryLoader.java b/jdk/src/share/classes/org/relaxng/datatype/helpers/DatatypeLibraryLoader.java
deleted file mode 100644
index a3091b08780..00000000000
--- a/jdk/src/share/classes/org/relaxng/datatype/helpers/DatatypeLibraryLoader.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/**
- * Copyright (c) 2001, Thai Open Source Software Center Ltd
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * Neither the name of the Thai Open Source Software Center Ltd nor
- * the names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.relaxng.datatype.helpers;
-
-import org.relaxng.datatype.DatatypeLibraryFactory;
-import org.relaxng.datatype.DatatypeLibrary;
-import java.util.Enumeration;
-import java.util.NoSuchElementException;
-import java.util.Vector;
-import java.io.Reader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URL;
-
-/**
- * Discovers the datatype library implementation from the classpath.
- *
- *
- * The call of the createDatatypeLibrary method finds an implementation
- * from a given datatype library URI at run-time.
- */
-public class DatatypeLibraryLoader implements DatatypeLibraryFactory {
- private final Service service = new Service(DatatypeLibraryFactory.class);
-
- public DatatypeLibrary createDatatypeLibrary(String uri) {
- for (Enumeration e = service.getProviders();
- e.hasMoreElements();) {
- DatatypeLibraryFactory factory
- = (DatatypeLibraryFactory)e.nextElement();
- DatatypeLibrary library = factory.createDatatypeLibrary(uri);
- if (library != null)
- return library;
- }
- return null;
- }
-
- private static class Service {
- private final Class serviceClass;
- private final Enumeration configFiles;
- private Enumeration classNames = null;
- private final Vector providers = new Vector();
- private Loader loader;
-
- private class ProviderEnumeration implements Enumeration {
- private int nextIndex = 0;
-
- public boolean hasMoreElements() {
- return nextIndex < providers.size() || moreProviders();
- }
-
- public Object nextElement() {
- try {
- return providers.elementAt(nextIndex++);
- }
- catch (ArrayIndexOutOfBoundsException e) {
- throw new NoSuchElementException();
- }
- }
- }
-
- private static class Singleton implements Enumeration {
- private Object obj;
- private Singleton(Object obj) {
- this.obj = obj;
- }
-
- public boolean hasMoreElements() {
- return obj != null;
- }
-
- public Object nextElement() {
- if (obj == null)
- throw new NoSuchElementException();
- Object tem = obj;
- obj = null;
- return tem;
- }
- }
-
- // JDK 1.1
- private static class Loader {
- Enumeration getResources(String resName) {
- ClassLoader cl = Loader.class.getClassLoader();
- URL url;
- if (cl == null)
- url = ClassLoader.getSystemResource(resName);
- else
- url = cl.getResource(resName);
- return new Singleton(url);
- }
-
- Class loadClass(String name) throws ClassNotFoundException {
- return Class.forName(name);
- }
- }
-
- // JDK 1.2+
- private static class Loader2 extends Loader {
- private ClassLoader cl;
-
- Loader2() {
- cl = Loader2.class.getClassLoader();
- // If the thread context class loader has the class loader
- // of this class as an ancestor, use the thread context class
- // loader. Otherwise, the thread context class loader
- // probably hasn't been set up properly, so don't use it.
- ClassLoader clt = Thread.currentThread().getContextClassLoader();
- for (ClassLoader tem = clt; tem != null; tem = tem.getParent())
- if (tem == cl) {
- cl = clt;
- break;
- }
- }
-
- Enumeration getResources(String resName) {
- try {
- return cl.getResources(resName);
-
- }
- catch (IOException e) {
- return new Singleton(null);
- }
- }
-
- Class loadClass(String name) throws ClassNotFoundException {
- return Class.forName(name, true, cl);
- }
- }
-
- public Service(Class cls) {
- try {
- loader = new Loader2();
- }
- catch (NoSuchMethodError e) {
- loader = new Loader();
- }
- serviceClass = cls;
- String resName = "META-INF/services/" + serviceClass.getName();
- configFiles = loader.getResources(resName);
- }
-
- public Enumeration getProviders() {
- return new ProviderEnumeration();
- }
-
- synchronized private boolean moreProviders() {
- for (;;) {
- while (classNames == null) {
- if (!configFiles.hasMoreElements())
- return false;
- classNames = parseConfigFile((URL)configFiles.nextElement());
- }
- while (classNames.hasMoreElements()) {
- String className = (String)classNames.nextElement();
- try {
- Class cls = loader.loadClass(className);
- Object obj = cls.newInstance();
- if (serviceClass.isInstance(obj)) {
- providers.addElement(obj);
- return true;
- }
- }
- catch (ClassNotFoundException e) { }
- catch (InstantiationException e) { }
- catch (IllegalAccessException e) { }
- catch (LinkageError e) { }
- }
- classNames = null;
- }
- }
-
- private static final int START = 0;
- private static final int IN_NAME = 1;
- private static final int IN_COMMENT = 2;
-
- private static Enumeration parseConfigFile(URL url) {
- try {
- InputStream in = url.openStream();
- Reader r;
- try {
- r = new InputStreamReader(in, "UTF-8");
- }
- catch (UnsupportedEncodingException e) {
- r = new InputStreamReader(in, "UTF8");
- }
- r = new BufferedReader(r);
- Vector tokens = new Vector();
- StringBuffer tokenBuf = new StringBuffer();
- int state = START;
- for (;;) {
- int n = r.read();
- if (n < 0)
- break;
- char c = (char)n;
- switch (c) {
- case '\r':
- case '\n':
- state = START;
- break;
- case ' ':
- case '\t':
- break;
- case '#':
- state = IN_COMMENT;
- break;
- default:
- if (state != IN_COMMENT) {
- state = IN_NAME;
- tokenBuf.append(c);
- }
- break;
- }
- if (tokenBuf.length() != 0 && state != IN_NAME) {
- tokens.addElement(tokenBuf.toString());
- tokenBuf.setLength(0);
- }
- }
- if (tokenBuf.length() != 0)
- tokens.addElement(tokenBuf.toString());
- return tokens.elements();
- }
- catch (IOException e) {
- return null;
- }
- }
- }
-
-}
diff --git a/jdk/src/share/classes/org/relaxng/datatype/helpers/ParameterlessDatatypeBuilder.java b/jdk/src/share/classes/org/relaxng/datatype/helpers/ParameterlessDatatypeBuilder.java
deleted file mode 100644
index 8a5efb8b2dd..00000000000
--- a/jdk/src/share/classes/org/relaxng/datatype/helpers/ParameterlessDatatypeBuilder.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 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.
- */
-
-package org.relaxng.datatype.helpers;
-
-import org.relaxng.datatype.*;
-
-/**
- * Dummy implementation of {@link DatatypeBuilder}.
- *
- * This implementation can be used for Datatypes which have no parameters.
- * Any attempt to add parameters will be rejected.
- *
- *
- * Typical usage would be:
- *
- * class MyDatatypeLibrary implements DatatypeLibrary {
- * ....
- * DatatypeBuilder createDatatypeBuilder( String typeName ) {
- * return new ParameterleessDatatypeBuilder(createDatatype(typeName));
- * }
- * ....
- * }
- *
- *
- * @author Kohsuke KAWAGUCHI
- */
-public final class ParameterlessDatatypeBuilder implements DatatypeBuilder {
-
- /** This type object is returned for the derive method. */
- private final Datatype baseType;
-
- public ParameterlessDatatypeBuilder( Datatype baseType ) {
- this.baseType = baseType;
- }
-
- public void addParameter( String name, String strValue, ValidationContext context )
- throws DatatypeException {
- throw new DatatypeException();
- }
-
- public Datatype createDatatype() throws DatatypeException {
- return baseType;
- }
-}
diff --git a/jdk/src/share/classes/org/relaxng/datatype/helpers/StreamingValidatorImpl.java b/jdk/src/share/classes/org/relaxng/datatype/helpers/StreamingValidatorImpl.java
deleted file mode 100644
index 5f7cc79e967..00000000000
--- a/jdk/src/share/classes/org/relaxng/datatype/helpers/StreamingValidatorImpl.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (c) 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.
- */
-
-package org.relaxng.datatype.helpers;
-
-import org.relaxng.datatype.*;
-
-/**
- * Dummy implementation of {@link DatatypeStreamingValidator}.
- *
- *
- * This implementation can be used as a quick hack when the performance
- * of streaming validation is not important. And this implementation
- * also shows you how to implement the DatatypeStreamingValidator interface.
- *
- *
- * Typical usage would be:
- *
- * class MyDatatype implements Datatype {
- * ....
- * public DatatypeStreamingValidator createStreamingValidator( ValidationContext context ) {
- * return new StreamingValidatorImpl(this,context);
- * }
- * ....
- * }
- *
- *
- * @author Kohsuke KAWAGUCHI
- */
-public final class StreamingValidatorImpl implements DatatypeStreamingValidator {
-
- /** This buffer accumulates characters. */
- private final StringBuffer buffer = new StringBuffer();
-
- /** Datatype obejct that creates this streaming validator. */
- private final Datatype baseType;
-
- /** The current context. */
- private final ValidationContext context;
-
- public void addCharacters( char[] buf, int start, int len ) {
- // append characters to the current buffer.
- buffer.append(buf,start,len);
- }
-
- public boolean isValid() {
- return baseType.isValid(buffer.toString(),context);
- }
-
- public void checkValid() throws DatatypeException {
- baseType.checkValid(buffer.toString(),context);
- }
-
- public StreamingValidatorImpl( Datatype baseType, ValidationContext context ) {
- this.baseType = baseType;
- this.context = context;
- }
-}
diff --git a/jdk/src/share/classes/overview-core.html b/jdk/src/share/classes/overview-core.html
index 86f33fe6ce9..c4b518c57b8 100644
--- a/jdk/src/share/classes/overview-core.html
+++ b/jdk/src/share/classes/overview-core.html
@@ -33,7 +33,7 @@ questions.
-This document is the API specification for version 6 of the Java™
+This document is the API specification for the Java™
Platform, Standard Edition.
diff --git a/jdk/src/share/classes/sun/awt/AWTAccessor.java b/jdk/src/share/classes/sun/awt/AWTAccessor.java
index 0e38de6df6f..b88531dfcd2 100644
--- a/jdk/src/share/classes/sun/awt/AWTAccessor.java
+++ b/jdk/src/share/classes/sun/awt/AWTAccessor.java
@@ -33,6 +33,9 @@ import java.awt.image.BufferedImage;
import sun.misc.Unsafe;
import java.awt.peer.ComponentPeer;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+
/**
* The AWTAccessor utility class.
* The main purpose of this class is to enable accessing
@@ -221,6 +224,13 @@ public final class AWTAccessor {
* Processes events occurring on this component.
*/
void processEvent(Component comp, AWTEvent e);
+
+
+ /*
+ * Returns the acc this component was constructed with.
+ */
+ AccessControlContext getAccessControlContext(Component comp);
+
}
/*
@@ -323,6 +333,13 @@ public final class AWTAccessor {
* Indicates whether this AWTEvent was generated by the system.
*/
boolean isSystemGenerated(AWTEvent ev);
+
+
+ /*
+ * Returns the acc this event was constructed with.
+ */
+ AccessControlContext getAccessControlContext(AWTEvent ev);
+
}
public interface InputEventAccessor {
diff --git a/jdk/src/share/classes/sun/dyn/Access.java b/jdk/src/share/classes/sun/dyn/Access.java
deleted file mode 100644
index 931303b03b6..00000000000
--- a/jdk/src/share/classes/sun/dyn/Access.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, 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 sun.dyn;
-
-import sun.reflect.Reflection;
-
-/**
- * Access control to this package.
- * Classes in other packages can attempt to acquire the access token,
- * but will fail if they are not recognized as friends.
- * Certain methods in this package, although public, require a non-null
- * access token in order to proceed; they act like package-private methods.
- * @author jrose
- */
-
-public class Access {
-
- private Access() { }
-
- /**
- * The heart of this pattern: The list of classes which are
- * permitted to acquire the access token, and become honorary
- * members of this package.
- */
- private static final String[] FRIENDS = {
- "java.dyn.", "sun.dyn."
- };
-
- /**
- * The following object is NOT public. That's the point of the pattern.
- * It is package-private, so that any member of this package
- * can acquire the access token, and give it away to trusted friends.
- */
- static final Access TOKEN = new Access();
-
- /**
- * @return Access.TOKEN, if the caller is a friend of this package
- */
- public static Access getToken() {
- Class> callc = Reflection.getCallerClass(2);
- if (isFriend(callc))
- return TOKEN;
- else
- throw new IllegalAccessError("bad caller: " + callc);
- }
-
- /** Is the given name the name of a class which could be our friend? */
- public static boolean isFriendName(String name) {
- for (String friend : FRIENDS) {
- if (name.startsWith(friend))
- return true;
- }
- return false;
- }
-
- /** Is the given class a friend? True if {@link #isFriendName},
- * and the given class also shares a class loader with us.
- */
- public static boolean isFriend(Class> c) {
- return isFriendName(c.getName()) && c.getClassLoader() == CLASS_LOADER;
- }
-
- private static final ClassLoader CLASS_LOADER = Access.class.getClassLoader();
-
- /**
- * Throw an IllegalAccessError if the caller does not possess
- * the Access.TOKEN.
- * @param must be Access.TOKEN
- */
- public static void check(Access token) {
- if (token == null)
- fail();
- // else it must be the unique Access.TOKEN
- assert(token == Access.TOKEN);
- }
- private static void fail() {
- final int CALLER_DEPTH = 3;
- // 0: Reflection.getCC, 1: this.fail, 2: Access.*, 3: caller
- Class> callc = Reflection.getCallerClass(CALLER_DEPTH);
- throw new IllegalAccessError("bad caller: " + callc);
- }
-
- static {
- //sun.reflect.Reflection.registerMethodsToFilter(MH.class, "getToken");
- }
-}
diff --git a/jdk/src/share/classes/sun/dyn/CallSiteImpl.java b/jdk/src/share/classes/sun/dyn/CallSiteImpl.java
deleted file mode 100644
index 703788ff484..00000000000
--- a/jdk/src/share/classes/sun/dyn/CallSiteImpl.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2008, 2010, 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 sun.dyn;
-
-import java.dyn.*;
-import static sun.dyn.MemberName.uncaughtException;
-
-/**
- * Parts of CallSite known to the JVM.
- * @author jrose
- */
-public class CallSiteImpl {
- // this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
- static CallSite makeSite(MethodHandle bootstrapMethod,
- // Callee information:
- String name, MethodType type,
- // Extra arguments for BSM, if any:
- Object info,
- // Caller information:
- MemberName callerMethod, int callerBCI) {
- Class> callerClass = callerMethod.getDeclaringClass();
- Object caller;
- if (bootstrapMethod.type().parameterType(0) == Class.class && TRANSITIONAL_BEFORE_PFD)
- caller = callerClass; // remove for PFD
- else
- caller = MethodHandleImpl.IMPL_LOOKUP.in(callerClass);
- if (bootstrapMethod == null && TRANSITIONAL_BEFORE_PFD) {
- // If there is no bootstrap method, throw IncompatibleClassChangeError.
- // This is a valid generic error type for resolution (JLS 12.3.3).
- throw new IncompatibleClassChangeError
- ("Class "+callerClass.getName()+" has not declared a bootstrap method for invokedynamic");
- }
- CallSite site;
- try {
- Object binding;
- info = maybeReBox(info);
- if (info == null) {
- binding = bootstrapMethod.invokeGeneric(caller, name, type);
- } else if (!info.getClass().isArray()) {
- binding = bootstrapMethod.invokeGeneric(caller, name, type, info);
- } else {
- Object[] argv = (Object[]) info;
- if (3 + argv.length > 255)
- new InvokeDynamicBootstrapError("too many bootstrap method arguments");
- MethodType bsmType = bootstrapMethod.type();
- if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class)
- binding = bootstrapMethod.invokeGeneric(caller, name, type, argv);
- else
- binding = MethodHandles.spreadInvoker(bsmType, 3)
- .invokeGeneric(bootstrapMethod, caller, name, type, argv);
- }
- //System.out.println("BSM for "+name+type+" => "+binding);
- if (binding instanceof CallSite) {
- site = (CallSite) binding;
- } else if (binding instanceof MethodHandle && TRANSITIONAL_BEFORE_PFD) {
- // Transitional!
- MethodHandle target = (MethodHandle) binding;
- site = new ConstantCallSite(target);
- } else {
- throw new ClassCastException("bootstrap method failed to produce a CallSite");
- }
- if (TRANSITIONAL_BEFORE_PFD)
- PRIVATE_INITIALIZE_CALL_SITE.invokeExact(site, name, type,
- callerMethod, callerBCI);
- assert(site.getTarget() != null);
- assert(site.getTarget().type().equals(type));
- } catch (Throwable ex) {
- InvokeDynamicBootstrapError bex;
- if (ex instanceof InvokeDynamicBootstrapError)
- bex = (InvokeDynamicBootstrapError) ex;
- else
- bex = new InvokeDynamicBootstrapError("call site initialization exception", ex);
- throw bex;
- }
- return site;
- }
-
- private static boolean TRANSITIONAL_BEFORE_PFD = true; // FIXME: remove for PFD
-
- private static Object maybeReBox(Object x) {
- if (x instanceof Integer) {
- int xi = (int) x;
- if (xi == (byte) xi)
- x = xi; // must rebox; see JLS 5.1.7
- return x;
- } else if (x instanceof Object[]) {
- Object[] xa = (Object[]) x;
- for (int i = 0; i < xa.length; i++) {
- if (xa[i] instanceof Integer)
- xa[i] = maybeReBox(xa[i]);
- }
- return xa;
- } else {
- return x;
- }
- }
-
- // This method is private in CallSite because it touches private fields in CallSite.
- // These private fields (vmmethod, vmindex) are specific to the JVM.
- private static final MethodHandle PRIVATE_INITIALIZE_CALL_SITE;
- static {
- try {
- PRIVATE_INITIALIZE_CALL_SITE =
- !TRANSITIONAL_BEFORE_PFD ? null :
- MethodHandleImpl.IMPL_LOOKUP.findVirtual(CallSite.class, "initializeFromJVM",
- MethodType.methodType(void.class,
- String.class, MethodType.class,
- MemberName.class, int.class));
- } catch (ReflectiveOperationException ex) {
- throw uncaughtException(ex);
- }
- }
-
- public static void setCallSiteTarget(Access token, CallSite site, MethodHandle target) {
- Access.check(token);
- MethodHandleNatives.setCallSiteTarget(site, target);
- }
-}
diff --git a/jdk/src/share/classes/sun/font/FileFont.java b/jdk/src/share/classes/sun/font/FileFont.java
index 22096dda2eb..1c63e9f1159 100644
--- a/jdk/src/share/classes/sun/font/FileFont.java
+++ b/jdk/src/share/classes/sun/font/FileFont.java
@@ -32,22 +32,13 @@ import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
import sun.java2d.Disposer;
import sun.java2d.DisposerRecord;
-import java.lang.ref.WeakReference;
-import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.io.UnsupportedEncodingException;
-import java.nio.ByteOrder;
-import java.nio.MappedByteBuffer;
-import java.nio.BufferUnderflowException;
-import java.nio.channels.ClosedChannelException;
-import java.util.HashSet;
-import java.util.HashMap;
-import java.awt.Font;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
public abstract class FileFont extends PhysicalFont {
@@ -286,4 +277,49 @@ public abstract class FileFont extends PhysicalFont {
});
}
}
+
+ protected String getPublicFileName() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm == null) {
+ return platName;
+ }
+ boolean canReadProperty = true;
+
+ try {
+ sm.checkPropertyAccess("java.io.tmpdir");
+ } catch (SecurityException e) {
+ canReadProperty = false;
+ }
+
+ if (canReadProperty) {
+ return platName;
+ }
+
+ final File f = new File(platName);
+
+ Boolean isTmpFile = Boolean.FALSE;
+ try {
+ isTmpFile = AccessController.doPrivileged(
+ new PrivilegedExceptionAction() {
+ public Boolean run() {
+ File tmp = new File(System.getProperty("java.io.tmpdir"));
+ try {
+ String tpath = tmp.getCanonicalPath();
+ String fpath = f.getCanonicalPath();
+
+ return (fpath == null) || fpath.startsWith(tpath);
+ } catch (IOException e) {
+ return Boolean.TRUE;
+ }
+ }
+ }
+ );
+ } catch (PrivilegedActionException e) {
+ // unable to verify whether value of java.io.tempdir will be
+ // exposed, so return only a name of the font file.
+ isTmpFile = Boolean.TRUE;
+ }
+
+ return isTmpFile ? "temp file" : platName;
+ }
}
diff --git a/jdk/src/share/classes/sun/font/TrueTypeFont.java b/jdk/src/share/classes/sun/font/TrueTypeFont.java
index e448338a3f3..84cbd2c9a34 100644
--- a/jdk/src/share/classes/sun/font/TrueTypeFont.java
+++ b/jdk/src/share/classes/sun/font/TrueTypeFont.java
@@ -519,7 +519,8 @@ public class TrueTypeFont extends FileFont {
break;
default:
- throw new FontFormatException("Unsupported sfnt " + platName);
+ throw new FontFormatException("Unsupported sfnt " +
+ getPublicFileName());
}
/* Now have the offset of this TT font (possibly within a TTC)
@@ -1680,7 +1681,6 @@ public class TrueTypeFont extends FileFont {
@Override
public String toString() {
return "** TrueType Font: Family="+familyName+ " Name="+fullName+
- " style="+style+" fileName="+platName;
+ " style="+style+" fileName="+getPublicFileName();
}
-
}
diff --git a/jdk/src/share/classes/sun/font/Type1Font.java b/jdk/src/share/classes/sun/font/Type1Font.java
index 48821dd94e5..5fa49bd132d 100644
--- a/jdk/src/share/classes/sun/font/Type1Font.java
+++ b/jdk/src/share/classes/sun/font/Type1Font.java
@@ -677,6 +677,6 @@ public class Type1Font extends FileFont {
public String toString() {
return "** Type1 Font: Family="+familyName+ " Name="+fullName+
- " style="+style+" fileName="+platName;
+ " style="+style+" fileName="+getPublicFileName();
}
}
diff --git a/jdk/src/share/classes/sun/dyn/WrapperInstance.java b/jdk/src/share/classes/sun/invoke/WrapperInstance.java
similarity index 90%
rename from jdk/src/share/classes/sun/dyn/WrapperInstance.java
rename to jdk/src/share/classes/sun/invoke/WrapperInstance.java
index d6e91fd0d03..ba918b4d9d2 100644
--- a/jdk/src/share/classes/sun/dyn/WrapperInstance.java
+++ b/jdk/src/share/classes/sun/invoke/WrapperInstance.java
@@ -23,14 +23,14 @@
* questions.
*/
-package sun.dyn;
+package sun.invoke;
-import java.dyn.MethodHandle;
+import java.lang.invoke.MethodHandle;
/**
- * Private API used inside of java.dyn.MethodHandles.
+ * Private API used inside of java.lang.invoke.MethodHandles.
* Interface implemented by every object which is produced by
- * {@link java.dyn.MethodHandles#asInstance MethodHandles.asInstance}.
+ * {@link java.lang.invoke.MethodHandles#asInstance MethodHandles.asInstance}.
* The methods of this interface allow a caller to recover the parameters
* to {@code asInstance}.
* This allows applications to repeatedly convert between method handles
diff --git a/jdk/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java b/jdk/src/share/classes/sun/invoke/anon/AnonymousClassLoader.java
similarity index 99%
rename from jdk/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java
rename to jdk/src/share/classes/sun/invoke/anon/AnonymousClassLoader.java
index bd7c5cb59dd..3005a452f71 100644
--- a/jdk/src/share/classes/sun/dyn/anon/AnonymousClassLoader.java
+++ b/jdk/src/share/classes/sun/invoke/anon/AnonymousClassLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,7 +23,7 @@
* questions.
*/
-package sun.dyn.anon;
+package sun.invoke.anon;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
diff --git a/jdk/src/share/classes/sun/dyn/anon/ConstantPoolParser.java b/jdk/src/share/classes/sun/invoke/anon/ConstantPoolParser.java
similarity index 99%
rename from jdk/src/share/classes/sun/dyn/anon/ConstantPoolParser.java
rename to jdk/src/share/classes/sun/invoke/anon/ConstantPoolParser.java
index b68b3f650c9..441ba957336 100644
--- a/jdk/src/share/classes/sun/dyn/anon/ConstantPoolParser.java
+++ b/jdk/src/share/classes/sun/invoke/anon/ConstantPoolParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,14 +23,14 @@
* questions.
*/
-package sun.dyn.anon;
+package sun.invoke.anon;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
-import static sun.dyn.anon.ConstantPoolVisitor.*;
+import static sun.invoke.anon.ConstantPoolVisitor.*;
/** A constant pool parser.
*/
diff --git a/jdk/src/share/classes/sun/dyn/anon/ConstantPoolPatch.java b/jdk/src/share/classes/sun/invoke/anon/ConstantPoolPatch.java
similarity index 99%
rename from jdk/src/share/classes/sun/dyn/anon/ConstantPoolPatch.java
rename to jdk/src/share/classes/sun/invoke/anon/ConstantPoolPatch.java
index 87dc97f6025..259d4b2336e 100644
--- a/jdk/src/share/classes/sun/dyn/anon/ConstantPoolPatch.java
+++ b/jdk/src/share/classes/sun/invoke/anon/ConstantPoolPatch.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,7 +23,7 @@
* questions.
*/
-package sun.dyn.anon;
+package sun.invoke.anon;
import java.io.IOException;
import java.io.OutputStream;
@@ -32,7 +32,7 @@ import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
-import static sun.dyn.anon.ConstantPoolVisitor.*;
+import static sun.invoke.anon.ConstantPoolVisitor.*;
/** A class and its patched constant pool.
*
diff --git a/jdk/src/share/classes/sun/dyn/anon/ConstantPoolVisitor.java b/jdk/src/share/classes/sun/invoke/anon/ConstantPoolVisitor.java
similarity index 98%
rename from jdk/src/share/classes/sun/dyn/anon/ConstantPoolVisitor.java
rename to jdk/src/share/classes/sun/invoke/anon/ConstantPoolVisitor.java
index e882b7d6724..dfec8b41151 100644
--- a/jdk/src/share/classes/sun/dyn/anon/ConstantPoolVisitor.java
+++ b/jdk/src/share/classes/sun/invoke/anon/ConstantPoolVisitor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,7 +23,7 @@
* questions.
*/
-package sun.dyn.anon;
+package sun.invoke.anon;
/**
* A visitor called by {@link ConstantPoolParser#parse(ConstantPoolVisitor)}
diff --git a/jdk/src/share/classes/sun/dyn/anon/InvalidConstantPoolFormatException.java b/jdk/src/share/classes/sun/invoke/anon/InvalidConstantPoolFormatException.java
similarity index 94%
rename from jdk/src/share/classes/sun/dyn/anon/InvalidConstantPoolFormatException.java
rename to jdk/src/share/classes/sun/invoke/anon/InvalidConstantPoolFormatException.java
index 555bb428f3f..d420d34b0d6 100644
--- a/jdk/src/share/classes/sun/dyn/anon/InvalidConstantPoolFormatException.java
+++ b/jdk/src/share/classes/sun/invoke/anon/InvalidConstantPoolFormatException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,7 +23,7 @@
* questions.
*/
-package sun.dyn.anon;
+package sun.invoke.anon;
/** Exception used when there is an error in the constant pool
* format.
diff --git a/jdk/src/share/classes/sun/dyn/empty/Empty.java b/jdk/src/share/classes/sun/invoke/empty/Empty.java
similarity index 90%
rename from jdk/src/share/classes/sun/dyn/empty/Empty.java
rename to jdk/src/share/classes/sun/invoke/empty/Empty.java
index 416a6f128e8..f75d2b3d016 100644
--- a/jdk/src/share/classes/sun/dyn/empty/Empty.java
+++ b/jdk/src/share/classes/sun/invoke/empty/Empty.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2011, 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
@@ -23,14 +23,14 @@
* questions.
*/
-package sun.dyn.empty;
+package sun.invoke.empty;
/**
* An empty class in an empty package.
* Used as a proxy for unprivileged code, since making access checks
* against it will only succeed against public methods in public types.
*
- * This class also stands (internally to sun.dyn) for the type of a
+ * This class also stands (internally to sun.invoke) for the type of a
* value that cannot be produced, because the expression of this type
* always returns abnormally. (Cf. Nothing in the closures proposal.)
* @author jrose
diff --git a/jdk/src/share/classes/sun/dyn/package-info.java b/jdk/src/share/classes/sun/invoke/package-info.java
similarity index 93%
rename from jdk/src/share/classes/sun/dyn/package-info.java
rename to jdk/src/share/classes/sun/invoke/package-info.java
index d129b0f5a27..74999fe6c7e 100644
--- a/jdk/src/share/classes/sun/dyn/package-info.java
+++ b/jdk/src/share/classes/sun/invoke/package-info.java
@@ -24,8 +24,8 @@
*/
/**
- * Implementation details for JSR 292 RI, package java.dyn.
+ * Implementation details for JSR 292 RI, package java.lang.invoke.
* @author jrose
*/
-package sun.dyn;
+package sun.invoke;
diff --git a/jdk/src/share/classes/sun/dyn/util/BytecodeDescriptor.java b/jdk/src/share/classes/sun/invoke/util/BytecodeDescriptor.java
similarity index 97%
rename from jdk/src/share/classes/sun/dyn/util/BytecodeDescriptor.java
rename to jdk/src/share/classes/sun/invoke/util/BytecodeDescriptor.java
index 2c59b918338..ccc313cd41b 100644
--- a/jdk/src/share/classes/sun/dyn/util/BytecodeDescriptor.java
+++ b/jdk/src/share/classes/sun/invoke/util/BytecodeDescriptor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,9 +23,9 @@
* questions.
*/
-package sun.dyn.util;
+package sun.invoke.util;
-import java.dyn.MethodType;
+import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
diff --git a/jdk/src/share/classes/sun/dyn/util/BytecodeName.java b/jdk/src/share/classes/sun/invoke/util/BytecodeName.java
similarity index 99%
rename from jdk/src/share/classes/sun/dyn/util/BytecodeName.java
rename to jdk/src/share/classes/sun/invoke/util/BytecodeName.java
index 73be3fb1361..9b8fa35cb70 100644
--- a/jdk/src/share/classes/sun/dyn/util/BytecodeName.java
+++ b/jdk/src/share/classes/sun/invoke/util/BytecodeName.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2011, 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
@@ -23,7 +23,7 @@
* questions.
*/
-package sun.dyn.util;
+package sun.invoke.util;
/**
* Utility routines for dealing with bytecode-level names.
diff --git a/jdk/src/share/classes/sun/dyn/util/ValueConversions.java b/jdk/src/share/classes/sun/invoke/util/ValueConversions.java
similarity index 94%
rename from jdk/src/share/classes/sun/dyn/util/ValueConversions.java
rename to jdk/src/share/classes/sun/invoke/util/ValueConversions.java
index 374bd245058..c6a56abf665 100644
--- a/jdk/src/share/classes/sun/dyn/util/ValueConversions.java
+++ b/jdk/src/share/classes/sun/invoke/util/ValueConversions.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,22 +23,19 @@
* questions.
*/
-package sun.dyn.util;
+package sun.invoke.util;
-import java.dyn.*;
-import java.dyn.MethodHandles.Lookup;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
-import sun.dyn.Access;
-import sun.dyn.AdapterMethodHandle;
-import sun.dyn.MethodHandleImpl;
-import static sun.dyn.MemberName.uncaughtException;
public class ValueConversions {
- private static final Access IMPL_TOKEN = Access.getToken();
- private static final Lookup IMPL_LOOKUP = MethodHandleImpl.getLookup(IMPL_TOKEN);
+ private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
private static EnumMap[] newWrapperCaches(int n) {
@SuppressWarnings("unchecked")
@@ -157,7 +154,7 @@ public class ValueConversions {
mh = null;
}
} else {
- mh = retype(type, unbox(wrap, !exact, raw));
+ mh = unbox(wrap, !exact, raw).asType(type);
}
if (mh != null) {
cache.put(wrap, mh);
@@ -293,7 +290,7 @@ public class ValueConversions {
mh = null;
}
} else {
- mh = retype(type.erase(), box(wrap, !exact, raw));
+ mh = box(wrap, !exact, raw).asType(type.erase());
}
if (mh != null) {
cache.put(wrap, mh);
@@ -412,7 +409,7 @@ public class ValueConversions {
mh = null;
}
} else {
- mh = retype(IDENTITY.type(), rebox(wrap, !exact));
+ mh = rebox(wrap, !exact).asType(IDENTITY.type());
}
if (mh != null) {
cache.put(wrap, mh);
@@ -504,8 +501,8 @@ public class ValueConversions {
// use the raw method
Wrapper rawWrap = wrap.rawPrimitive();
- if (rawWrap != wrap) {
- mh = retype(type, zeroConstantFunction(rawWrap));
+ if (mh == null && rawWrap != wrap) {
+ mh = MethodHandles.explicitCastArguments(zeroConstantFunction(rawWrap), type);
}
if (mh != null) {
cache.put(wrap, mh);
@@ -552,6 +549,22 @@ public class ValueConversions {
return x;
}
+ static byte identity(byte x) {
+ return x;
+ }
+
+ static short identity(short x) {
+ return x;
+ }
+
+ static boolean identity(boolean x) {
+ return x;
+ }
+
+ static char identity(char x) {
+ return x;
+ }
+
/**
* Identity function on longs.
* @param x an arbitrary long value
@@ -561,6 +574,14 @@ public class ValueConversions {
return x;
}
+ static float identity(float x) {
+ return x;
+ }
+
+ static double identity(double x) {
+ return x;
+ }
+
/**
* Identity function, with reference cast.
* @param t an arbitrary reference type
@@ -590,7 +611,9 @@ public class ValueConversions {
IGNORE = IMPL_LOOKUP.findStatic(ValueConversions.class, "ignore", ignoreType);
EMPTY = IMPL_LOOKUP.findStatic(ValueConversions.class, "empty", ignoreType.dropParameterTypes(0, 1));
} catch (Exception ex) {
- throw uncaughtException(ex);
+ Error err = new InternalError("uncaught exception");
+ err.initCause(ex);
+ throw err;
}
}
@@ -622,7 +645,8 @@ public class ValueConversions {
mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type);
if (exact) {
MethodType xmt = MethodType.methodType(type, Object.class);
- mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh);
+ mh = MethodHandles.explicitCastArguments(mh, xmt);
+ //mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh);
}
if (cache != null)
cache.put(wrap, mh);
@@ -634,15 +658,11 @@ public class ValueConversions {
}
public static MethodHandle identity(Class> type) {
- if (type == Object.class)
- return IDENTITY;
- else if (!type.isPrimitive())
- return retype(MethodType.methodType(type, type), IDENTITY);
- else
- return identity(Wrapper.forPrimitiveType(type));
+ // This stuff has been moved into MethodHandles:
+ return MethodHandles.identity(type);
}
- static MethodHandle identity(Wrapper wrap) {
+ public static MethodHandle identity(Wrapper wrap) {
EnumMap cache = CONSTANT_FUNCTIONS[1];
MethodHandle mh = cache.get(wrap);
if (mh != null) {
@@ -665,12 +685,6 @@ public class ValueConversions {
return mh;
}
- // use a raw conversion
- if (wrap.isSingleWord() && wrap != Wrapper.INT) {
- mh = retype(type, identity(Wrapper.INT));
- } else if (wrap.isDoubleWord() && wrap != Wrapper.LONG) {
- mh = retype(type, identity(Wrapper.LONG));
- }
if (mh != null) {
cache.put(wrap, mh);
return mh;
@@ -678,10 +692,6 @@ public class ValueConversions {
throw new IllegalArgumentException("cannot find identity for " + wrap);
}
- private static MethodHandle retype(MethodType type, MethodHandle mh) {
- return AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, type, mh);
- }
-
private static final Object[] NO_ARGS_ARRAY = {};
private static Object[] makeArray(Object... args) { return args; }
private static Object[] array() { return NO_ARGS_ARRAY; }
diff --git a/jdk/src/share/classes/sun/dyn/util/VerifyAccess.java b/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java
similarity index 98%
rename from jdk/src/share/classes/sun/dyn/util/VerifyAccess.java
rename to jdk/src/share/classes/sun/invoke/util/VerifyAccess.java
index 1114bad2695..657aeec23d8 100644
--- a/jdk/src/share/classes/sun/dyn/util/VerifyAccess.java
+++ b/jdk/src/share/classes/sun/invoke/util/VerifyAccess.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,12 +23,9 @@
* questions.
*/
-package sun.dyn.util;
+package sun.invoke.util;
import java.lang.reflect.Modifier;
-import sun.dyn.MemberName;
-import sun.dyn.MethodHandleImpl;
-import sun.dyn.empty.Empty;
import static java.lang.reflect.Modifier.*;
/**
diff --git a/jdk/src/share/classes/sun/dyn/util/VerifyType.java b/jdk/src/share/classes/sun/invoke/util/VerifyType.java
similarity index 98%
rename from jdk/src/share/classes/sun/dyn/util/VerifyType.java
rename to jdk/src/share/classes/sun/invoke/util/VerifyType.java
index b6277e4a8a9..39286d09ca4 100644
--- a/jdk/src/share/classes/sun/dyn/util/VerifyType.java
+++ b/jdk/src/share/classes/sun/invoke/util/VerifyType.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,10 +23,10 @@
* questions.
*/
-package sun.dyn.util;
+package sun.invoke.util;
-import java.dyn.MethodType;
-import sun.dyn.empty.Empty;
+import java.lang.invoke.MethodType;
+import sun.invoke.empty.Empty;
/**
* This class centralizes information about the JVM verifier
diff --git a/jdk/src/share/classes/sun/dyn/util/Wrapper.java b/jdk/src/share/classes/sun/invoke/util/Wrapper.java
similarity index 99%
rename from jdk/src/share/classes/sun/dyn/util/Wrapper.java
rename to jdk/src/share/classes/sun/invoke/util/Wrapper.java
index 91b599e8c64..8e2ce578386 100644
--- a/jdk/src/share/classes/sun/dyn/util/Wrapper.java
+++ b/jdk/src/share/classes/sun/invoke/util/Wrapper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -23,7 +23,7 @@
* questions.
*/
-package sun.dyn.util;
+package sun.invoke.util;
public enum Wrapper {
BOOLEAN(Boolean.class, boolean.class, 'Z', (Boolean)false, Format.unsigned(1)),
@@ -267,7 +267,7 @@ public enum Wrapper {
FROM_WRAP[wi] = w;
FROM_CHAR[ci] = w;
}
- //assert(jdk.sun.dyn.util.WrapperTest.test(false));
+ //assert(jdk.sun.invoke.util.WrapperTest.test(false));
}
/** What is the primitive type wrapped by this wrapper? */
diff --git a/jdk/src/share/classes/sun/dyn/util/package-info.java b/jdk/src/share/classes/sun/invoke/util/package-info.java
similarity index 88%
rename from jdk/src/share/classes/sun/dyn/util/package-info.java
rename to jdk/src/share/classes/sun/invoke/util/package-info.java
index 0977b22ef94..785ca804302 100644
--- a/jdk/src/share/classes/sun/dyn/util/package-info.java
+++ b/jdk/src/share/classes/sun/invoke/util/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2011, 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
@@ -24,8 +24,8 @@
*/
/**
- * Extra support for using JSR 292 RI, package java.dyn.
+ * Extra support for using JSR 292 RI, package java.lang.invoke.
* @author jrose
*/
-package sun.dyn.util;
+package sun.invoke.util;
diff --git a/jdk/src/share/classes/sun/java2d/pisces/Helpers.java b/jdk/src/share/classes/sun/java2d/pisces/Helpers.java
index b91bc6a400a..42c7f2654d3 100644
--- a/jdk/src/share/classes/sun/java2d/pisces/Helpers.java
+++ b/jdk/src/share/classes/sun/java2d/pisces/Helpers.java
@@ -154,9 +154,6 @@ final class Helpers {
// These use a hardcoded factor of 2 for increasing sizes. Perhaps this
// should be provided as an argument.
static float[] widenArray(float[] in, final int cursize, final int numToAdd) {
- if (in == null) {
- return new float[5 * numToAdd];
- }
if (in.length >= cursize + numToAdd) {
return in;
}
diff --git a/jdk/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java b/jdk/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java
index ba91edb9819..3d6046bed69 100644
--- a/jdk/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java
+++ b/jdk/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java
@@ -191,8 +191,7 @@ final class PiscesTileGenerator implements AATileGenerator {
System.out.println("len = "+runLen);
System.out.print(cache.toString());
e0.printStackTrace();
- System.exit(1);
- return;
+ throw e0;
}
int rx0 = cx;
@@ -215,8 +214,7 @@ final class PiscesTileGenerator implements AATileGenerator {
System.out.println("len = "+runLen);
System.out.print(cache.toString());
e.printStackTrace();
- System.exit(1);
- return;
+ throw e;
}
}
pos += 2;
@@ -250,4 +248,5 @@ final class PiscesTileGenerator implements AATileGenerator {
* No further calls will be made on this instance.
*/
public void dispose() {}
-}
\ No newline at end of file
+}
+
diff --git a/jdk/src/share/classes/sun/java2d/pisces/Renderer.java b/jdk/src/share/classes/sun/java2d/pisces/Renderer.java
index cbfa2897d94..6d07b532e08 100644
--- a/jdk/src/share/classes/sun/java2d/pisces/Renderer.java
+++ b/jdk/src/share/classes/sun/java2d/pisces/Renderer.java
@@ -47,16 +47,16 @@ final class Renderer implements PathConsumer2D {
private static final int INIT_CROSSINGS_SIZE = 10;
- private ScanlineIterator() {
+ // Preconditions: Only subpixel scanlines in the range
+ // (start <= subpixel_y <= end) will be evaluated. No
+ // edge may have a valid (i.e. inside the supplied clip)
+ // crossing that would be generated outside that range.
+ private ScanlineIterator(int start, int end) {
crossings = new int[INIT_CROSSINGS_SIZE];
edgePtrs = new int[INIT_CROSSINGS_SIZE];
- // We don't care if we clip some of the line off with ceil, since
- // no scan line crossings will be eliminated (in fact, the ceil is
- // the y of the first scan line crossing).
- final int minY = getFirstScanLineCrossing();
- nextY = minY;
- maxY = getScanLineCrossingEnd()-1;
+ nextY = start;
+ maxY = end;
edgeCount = 0;
}
@@ -148,6 +148,7 @@ final class Renderer implements PathConsumer2D {
// don't just set NULL to -1, because we want NULL+NEXT to be negative.
private static final int NULL = -SIZEOF_EDGE;
private float[] edges = null;
+ private static final int INIT_NUM_EDGES = 8;
private int[] edgeBuckets = null;
private int[] edgeBucketCounts = null; // 2*newedges + (1 if pruning needed)
private int numEdges;
@@ -156,7 +157,7 @@ final class Renderer implements PathConsumer2D {
private static final float INC_BND = 8f;
// each bucket is a linked list. this method adds eptr to the
- // start "bucket"th linked list.
+ // start of the "bucket"th linked list.
private void addEdgeToBucket(final int eptr, final int bucket) {
edges[eptr+NEXT] = edgeBuckets[bucket];
edgeBuckets[bucket] = eptr;
@@ -168,7 +169,8 @@ final class Renderer implements PathConsumer2D {
// X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
private void quadBreakIntoLinesAndAdd(float x0, float y0,
final Curve c,
- final float x2, final float y2) {
+ final float x2, final float y2)
+ {
final float QUAD_DEC_BND = 32;
final int countlg = 4;
int count = 1 << countlg;
@@ -204,7 +206,8 @@ final class Renderer implements PathConsumer2D {
// here, but then too many numbers are passed around.
private void curveBreakIntoLinesAndAdd(float x0, float y0,
final Curve c,
- final float x3, final float y3) {
+ final float x3, final float y3)
+ {
final int countlg = 3;
int count = 1 << countlg;
@@ -259,8 +262,6 @@ final class Renderer implements PathConsumer2D {
}
}
- // Preconditions: y2 > y1 and the curve must cross some scanline
- // i.e.: y1 <= y < y2 for some y such that boundsMinY <= y < boundsMaxY
private void addLine(float x1, float y1, float x2, float y2) {
float or = 1; // orientation of the line. 1 if y increases, 0 otherwise.
if (y2 < y1) {
@@ -272,12 +273,11 @@ final class Renderer implements PathConsumer2D {
x1 = or;
or = 0;
}
- final int firstCrossing = Math.max((int) Math.ceil(y1), boundsMinY);
+ final int firstCrossing = Math.max((int)Math.ceil(y1), boundsMinY);
final int lastCrossing = Math.min((int)Math.ceil(y2), boundsMaxY);
if (firstCrossing >= lastCrossing) {
return;
}
-
if (y1 < edgeMinY) { edgeMinY = y1; }
if (y2 > edgeMaxY) { edgeMaxY = y2; }
@@ -297,22 +297,10 @@ final class Renderer implements PathConsumer2D {
edges[ptr+OR] = or;
edges[ptr+CURX] = x1 + (firstCrossing - y1) * slope;
edges[ptr+SLOPE] = slope;
- edges[ptr+YMAX] = y2;
+ edges[ptr+YMAX] = lastCrossing;
final int bucketIdx = firstCrossing - boundsMinY;
addEdgeToBucket(ptr, bucketIdx);
- if (lastCrossing < boundsMaxY) {
- edgeBucketCounts[lastCrossing - boundsMinY] |= 1;
- }
- }
-
- // preconditions: should not be called before the last line has been added
- // to the edge list (even though it will return a correct answer at that
- // point in time, it's not meant to be used that way).
- private int getFirstScanLineCrossing() {
- return Math.max(boundsMinY, (int)Math.ceil(edgeMinY));
- }
- private int getScanLineCrossingEnd() {
- return Math.min(boundsMaxY, (int)Math.ceil(edgeMaxY));
+ edgeBucketCounts[lastCrossing - boundsMinY] |= 1;
}
// END EDGE LIST
@@ -366,9 +354,11 @@ final class Renderer implements PathConsumer2D {
this.boundsMaxX = (pix_boundsX + pix_boundsWidth) * SUBPIXEL_POSITIONS_X;
this.boundsMaxY = (pix_boundsY + pix_boundsHeight) * SUBPIXEL_POSITIONS_Y;
+ edges = new float[INIT_NUM_EDGES * SIZEOF_EDGE];
+ numEdges = 0;
edgeBuckets = new int[boundsMaxY - boundsMinY];
java.util.Arrays.fill(edgeBuckets, NULL);
- edgeBucketCounts = new int[edgeBuckets.length];
+ edgeBucketCounts = new int[edgeBuckets.length + 1];
}
private float tosubpixx(float pix_x) {
@@ -394,7 +384,7 @@ final class Renderer implements PathConsumer2D {
y0 = y1;
}
- Curve c = new Curve();
+ private Curve c = new Curve();
@Override public void curveTo(float x1, float y1,
float x2, float y2,
float x3, float y3)
@@ -431,8 +421,8 @@ final class Renderer implements PathConsumer2D {
throw new InternalError("Renderer does not use a native consumer.");
}
- private void _endRendering(final int pix_bboxx0, final int pix_bboxy0,
- final int pix_bboxx1, final int pix_bboxy1)
+ private void _endRendering(final int pix_bboxx0, final int pix_bboxx1,
+ int ymin, int ymax)
{
// Mask to determine the relevant bit of the crossing sum
// 0x1 if EVEN_ODD, all bits if NON_ZERO
@@ -455,7 +445,7 @@ final class Renderer implements PathConsumer2D {
int pix_minX = Integer.MAX_VALUE;
int y = boundsMinY; // needs to be declared here so we emit the last row properly.
- ScanlineIterator it = this.new ScanlineIterator();
+ ScanlineIterator it = this.new ScanlineIterator(ymin, ymax);
for ( ; it.hasNext(); ) {
int numCrossings = it.next();
int[] crossings = it.crossings;
@@ -477,7 +467,7 @@ final class Renderer implements PathConsumer2D {
int curxo = crossings[i];
int curx = curxo >> 1;
// to turn {0, 1} into {-1, 1}, multiply by 2 and subtract 1.
- int crorientation = ((curxo & 0x1) << 1) -1;
+ int crorientation = ((curxo & 0x1) << 1) - 1;
if ((sum & mask) != 0) {
int x0 = Math.max(prev, bboxx0);
int x1 = Math.min(curx, bboxx1);
@@ -541,7 +531,7 @@ final class Renderer implements PathConsumer2D {
}
this.cache = new PiscesCache(pminX, pminY, pmaxX, pmaxY);
- _endRendering(pminX, pminY, pmaxX, pmaxY);
+ _endRendering(pminX, pmaxX, spminY, spmaxY);
}
public PiscesCache getCache() {
diff --git a/jdk/src/share/classes/sun/java2d/pisces/Stroker.java b/jdk/src/share/classes/sun/java2d/pisces/Stroker.java
index b898febc4c2..f7323f95adb 100644
--- a/jdk/src/share/classes/sun/java2d/pisces/Stroker.java
+++ b/jdk/src/share/classes/sun/java2d/pisces/Stroker.java
@@ -764,6 +764,11 @@ final class Stroker implements PathConsumer2D {
private static final int MAX_N_CURVES = 11;
private float[] subdivTs = new float[MAX_N_CURVES - 1];
+ // If this class is compiled with ecj, then Hotspot crashes when OSR
+ // compiling this function. See bugs 7004570 and 6675699
+ // TODO: until those are fixed, we should work around that by
+ // manually inlining this into curveTo and quadTo.
+/******************************* WORKAROUND **********************************
private void somethingTo(final int type) {
// need these so we can update the state at the end of this method
final float xf = middle[type-2], yf = middle[type-1];
@@ -866,6 +871,7 @@ final class Stroker implements PathConsumer2D {
this.cy0 = yf;
this.prev = DRAWING_OP_TO;
}
+****************************** END WORKAROUND *******************************/
// finds values of t where the curve in pts should be subdivided in order
// to get good offset curves a distance of w away from the middle curve.
@@ -932,18 +938,168 @@ final class Stroker implements PathConsumer2D {
middle[2] = x1; middle[3] = y1;
middle[4] = x2; middle[5] = y2;
middle[6] = x3; middle[7] = y3;
- somethingTo(8);
- }
- @Override public long getNativeConsumer() {
- throw new InternalError("Stroker doesn't use a native consumer");
+ // inlined version of somethingTo(8);
+ // See the TODO on somethingTo
+
+ // need these so we can update the state at the end of this method
+ final float xf = middle[6], yf = middle[7];
+ float dxs = middle[2] - middle[0];
+ float dys = middle[3] - middle[1];
+ float dxf = middle[6] - middle[4];
+ float dyf = middle[7] - middle[5];
+
+ boolean p1eqp2 = (dxs == 0f && dys == 0f);
+ boolean p3eqp4 = (dxf == 0f && dyf == 0f);
+ if (p1eqp2) {
+ dxs = middle[4] - middle[0];
+ dys = middle[5] - middle[1];
+ if (dxs == 0f && dys == 0f) {
+ dxs = middle[6] - middle[0];
+ dys = middle[7] - middle[1];
+ }
+ }
+ if (p3eqp4) {
+ dxf = middle[6] - middle[2];
+ dyf = middle[7] - middle[3];
+ if (dxf == 0f && dyf == 0f) {
+ dxf = middle[6] - middle[0];
+ dyf = middle[7] - middle[1];
+ }
+ }
+ if (dxs == 0f && dys == 0f) {
+ // this happens iff the "curve" is just a point
+ lineTo(middle[0], middle[1]);
+ return;
+ }
+
+ // if these vectors are too small, normalize them, to avoid future
+ // precision problems.
+ if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
+ float len = (float)Math.sqrt(dxs*dxs + dys*dys);
+ dxs /= len;
+ dys /= len;
+ }
+ if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
+ float len = (float)Math.sqrt(dxf*dxf + dyf*dyf);
+ dxf /= len;
+ dyf /= len;
+ }
+
+ computeOffset(dxs, dys, lineWidth2, offset[0]);
+ final float mx = offset[0][0];
+ final float my = offset[0][1];
+ drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, mx, my);
+
+ int nSplits = findSubdivPoints(middle, subdivTs, 8, lineWidth2);
+
+ int kind = 0;
+ Iterator it = Curve.breakPtsAtTs(middle, 8, subdivTs, nSplits);
+ while(it.hasNext()) {
+ int curCurveOff = it.next();
+
+ kind = computeOffsetCubic(middle, curCurveOff, lp, rp);
+ if (kind != 0) {
+ emitLineTo(lp[0], lp[1]);
+ switch(kind) {
+ case 8:
+ emitCurveTo(lp[0], lp[1], lp[2], lp[3], lp[4], lp[5], lp[6], lp[7], false);
+ emitCurveTo(rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7], true);
+ break;
+ case 4:
+ emitLineTo(lp[2], lp[3]);
+ emitLineTo(rp[0], rp[1], true);
+ break;
+ }
+ emitLineTo(rp[kind - 2], rp[kind - 1], true);
+ }
+ }
+
+ this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
+ this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
+ this.cdx = dxf;
+ this.cdy = dyf;
+ this.cx0 = xf;
+ this.cy0 = yf;
+ this.prev = DRAWING_OP_TO;
}
@Override public void quadTo(float x1, float y1, float x2, float y2) {
middle[0] = cx0; middle[1] = cy0;
middle[2] = x1; middle[3] = y1;
middle[4] = x2; middle[5] = y2;
- somethingTo(6);
+
+ // inlined version of somethingTo(8);
+ // See the TODO on somethingTo
+
+ // need these so we can update the state at the end of this method
+ final float xf = middle[4], yf = middle[5];
+ float dxs = middle[2] - middle[0];
+ float dys = middle[3] - middle[1];
+ float dxf = middle[4] - middle[2];
+ float dyf = middle[5] - middle[3];
+ if ((dxs == 0f && dys == 0f) || (dxf == 0f && dyf == 0f)) {
+ dxs = dxf = middle[4] - middle[0];
+ dys = dyf = middle[5] - middle[1];
+ }
+ if (dxs == 0f && dys == 0f) {
+ // this happens iff the "curve" is just a point
+ lineTo(middle[0], middle[1]);
+ return;
+ }
+ // if these vectors are too small, normalize them, to avoid future
+ // precision problems.
+ if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
+ float len = (float)Math.sqrt(dxs*dxs + dys*dys);
+ dxs /= len;
+ dys /= len;
+ }
+ if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
+ float len = (float)Math.sqrt(dxf*dxf + dyf*dyf);
+ dxf /= len;
+ dyf /= len;
+ }
+
+ computeOffset(dxs, dys, lineWidth2, offset[0]);
+ final float mx = offset[0][0];
+ final float my = offset[0][1];
+ drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, mx, my);
+
+ int nSplits = findSubdivPoints(middle, subdivTs, 6, lineWidth2);
+
+ int kind = 0;
+ Iterator it = Curve.breakPtsAtTs(middle, 6, subdivTs, nSplits);
+ while(it.hasNext()) {
+ int curCurveOff = it.next();
+
+ kind = computeOffsetQuad(middle, curCurveOff, lp, rp);
+ if (kind != 0) {
+ emitLineTo(lp[0], lp[1]);
+ switch(kind) {
+ case 6:
+ emitQuadTo(lp[0], lp[1], lp[2], lp[3], lp[4], lp[5], false);
+ emitQuadTo(rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], true);
+ break;
+ case 4:
+ emitLineTo(lp[2], lp[3]);
+ emitLineTo(rp[0], rp[1], true);
+ break;
+ }
+ emitLineTo(rp[kind - 2], rp[kind - 1], true);
+ }
+ }
+
+ this.cmx = (lp[kind - 2] - rp[kind - 2]) / 2;
+ this.cmy = (lp[kind - 1] - rp[kind - 1]) / 2;
+ this.cdx = dxf;
+ this.cdy = dyf;
+ this.cx0 = xf;
+ this.cy0 = yf;
+ this.prev = DRAWING_OP_TO;
+ }
+
+ @Override public long getNativeConsumer() {
+ throw new InternalError("Stroker doesn't use a native consumer");
}
// a stack of polynomial curves where each curve shares endpoints with
diff --git a/jdk/src/share/classes/sun/launcher/LauncherHelper.java b/jdk/src/share/classes/sun/launcher/LauncherHelper.java
index ff71e8908b1..bd0b72e47ab 100644
--- a/jdk/src/share/classes/sun/launcher/LauncherHelper.java
+++ b/jdk/src/share/classes/sun/launcher/LauncherHelper.java
@@ -42,10 +42,12 @@ package sun.launcher;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.RoundingMode;
+import java.nio.charset.Charset;
import java.util.ResourceBundle;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -471,11 +473,11 @@ public enum LauncherHelper {
} catch (ClassNotFoundException cnfe) {
abort(ostream, cnfe, "java.launcher.cls.error1", cn);
}
- signatureDiagnostic(ostream, c);
+ getMainMethod(ostream, c);
return c;
}
- static void signatureDiagnostic(PrintStream ostream, Class> clazz) {
+ static Method getMainMethod(PrintStream ostream, Class> clazz) {
String classname = clazz.getName();
Method method = null;
try {
@@ -495,6 +497,31 @@ public enum LauncherHelper {
if (method.getReturnType() != java.lang.Void.TYPE) {
abort(ostream, null, "java.launcher.cls.error3", classname);
}
- return;
+ return method;
+ }
+
+ private static final String encprop = "sun.jnu.encoding";
+ private static String encoding = null;
+ private static boolean isCharsetSupported = false;
+
+ /*
+ * converts a c or a byte array to a platform specific string,
+ * previously implemented as a native method in the launcher.
+ */
+ static String makePlatformString(boolean printToStderr, byte[] inArray) {
+ final PrintStream ostream = (printToStderr) ? System.err : System.out;
+ if (encoding == null) {
+ encoding = System.getProperty(encprop);
+ isCharsetSupported = Charset.isSupported(encoding);
+ }
+ try {
+ String out = isCharsetSupported
+ ? new String(inArray, encoding)
+ : new String(inArray);
+ return out;
+ } catch (UnsupportedEncodingException uee) {
+ abort(ostream, uee, null);
+ }
+ return null; // keep the compiler happy
}
}
diff --git a/jdk/src/share/classes/java/dyn/MethodTypeForm.java b/jdk/src/share/classes/sun/misc/JavaSecurityAccess.java
similarity index 68%
rename from jdk/src/share/classes/java/dyn/MethodTypeForm.java
rename to jdk/src/share/classes/sun/misc/JavaSecurityAccess.java
index 35c59a45c0c..5a3aa513fb8 100644
--- a/jdk/src/share/classes/java/dyn/MethodTypeForm.java
+++ b/jdk/src/share/classes/sun/misc/JavaSecurityAccess.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 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
@@ -23,17 +23,18 @@
* questions.
*/
-package java.dyn;
+package sun.misc;
-/**
- * TO DO: Temporary shim; remove after refactoring effects are complete in JVM.
- * @author John Rose
- */
-import sun.dyn.MethodTypeImpl;
+import java.security.AccessControlContext;
+import java.security.PrivilegedAction;
-class MethodTypeForm extends MethodTypeImpl {
+public interface JavaSecurityAccess {
+
+ T doIntersectionPrivilege(PrivilegedAction action,
+ AccessControlContext stack,
+ AccessControlContext context);
+
+ T doIntersectionPrivilege(PrivilegedAction action,
+ AccessControlContext context);
- MethodTypeForm(MethodType erasedType) {
- super(erasedType);
- }
}
diff --git a/jdk/src/share/classes/sun/misc/SharedSecrets.java b/jdk/src/share/classes/sun/misc/SharedSecrets.java
index 2335b2d68b5..0bd39b4a5d4 100644
--- a/jdk/src/share/classes/sun/misc/SharedSecrets.java
+++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java
@@ -30,6 +30,8 @@ import java.io.Console;
import java.io.FileDescriptor;
import java.security.ProtectionDomain;
+import java.security.AccessController;
+
/** A repository of "shared secrets", which are a mechanism for
calling implementation-private methods in another package without
using reflection. A package-private class implements a public
@@ -48,6 +50,7 @@ public class SharedSecrets {
private static JavaNioAccess javaNioAccess;
private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess;
+ private static JavaSecurityAccess javaSecurityAccess;
public static JavaUtilJarAccess javaUtilJarAccess() {
if (javaUtilJarAccess == null) {
@@ -125,4 +128,15 @@ public class SharedSecrets {
unsafe.ensureClassInitialized(ProtectionDomain.class);
return javaSecurityProtectionDomainAccess;
}
+
+ public static void setJavaSecurityAccess(JavaSecurityAccess jsa) {
+ javaSecurityAccess = jsa;
+ }
+
+ public static JavaSecurityAccess getJavaSecurityAccess() {
+ if (javaSecurityAccess == null) {
+ unsafe.ensureClassInitialized(AccessController.class);
+ }
+ return javaSecurityAccess;
+ }
}
diff --git a/jdk/src/share/classes/sun/net/ResourceManager.java b/jdk/src/share/classes/sun/net/ResourceManager.java
new file mode 100644
index 00000000000..11bfc464819
--- /dev/null
+++ b/jdk/src/share/classes/sun/net/ResourceManager.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011, 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 sun.net;
+
+import java.net.SocketException;
+import java.util.concurrent.atomic.AtomicInteger;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Manages count of total number of UDP sockets and ensures
+ * that exception is thrown if we try to create more than the
+ * configured limit.
+ *
+ * This functionality could be put in NetHooks some time in future.
+ */
+
+public class ResourceManager {
+
+ /* default maximum number of udp sockets per VM
+ * when a security manager is enabled.
+ * The default is 1024 which is high enough to be useful
+ * but low enough to be well below the maximum number
+ * of port numbers actually available on all OSes for
+ * such sockets (5000 on some versions of windows)
+ */
+
+ private static final int DEFAULT_MAX_SOCKETS = 1024;
+ private static final int maxSockets;
+ private static final AtomicInteger numSockets;
+
+ static {
+ String prop = java.security.AccessController.doPrivileged(
+ new GetPropertyAction("sun.net.maxDatagramSockets")
+ );
+ int defmax = DEFAULT_MAX_SOCKETS;
+ try {
+ if (prop != null) {
+ defmax = Integer.parseInt(prop);
+ }
+ } catch (NumberFormatException e) {}
+ maxSockets = defmax;
+ numSockets = new AtomicInteger(0);
+ }
+
+ public static void beforeUdpCreate() throws SocketException {
+ if (System.getSecurityManager() != null) {
+ if (numSockets.incrementAndGet() > maxSockets) {
+ numSockets.decrementAndGet();
+ throw new SocketException("maximum number of DatagramSockets reached");
+ }
+ }
+ }
+
+ public static void afterUdpClose() {
+ if (System.getSecurityManager() != null) {
+ numSockets.decrementAndGet();
+ }
+ }
+}
diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
index 69f12a5c601..afc8cea0308 100644
--- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
@@ -2173,6 +2173,13 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (tryTransparentNTLMServer) {
tryTransparentNTLMServer =
NTLMAuthenticationProxy.proxy.supportsTransparentAuth;
+ /* If the platform supports transparent authentication
+ * then check if we are in a secure environment
+ * whether, or not, we should try transparent authentication.*/
+ if (tryTransparentNTLMServer) {
+ tryTransparentNTLMServer =
+ NTLMAuthenticationProxy.proxy.isTrustedSite(url);
+ }
}
a = null;
if (tryTransparentNTLMServer) {
diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java b/jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java
index a998d2b1226..b235a0bed17 100644
--- a/jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java
@@ -36,12 +36,14 @@ import sun.util.logging.PlatformLogger;
*/
class NTLMAuthenticationProxy {
private static Method supportsTA;
+ private static Method isTrustedSite;
private static final String clazzStr = "sun.net.www.protocol.http.ntlm.NTLMAuthentication";
private static final String supportsTAStr = "supportsTransparentAuth";
+ private static final String isTrustedSiteStr = "isTrustedSite";
static final NTLMAuthenticationProxy proxy = tryLoadNTLMAuthentication();
static final boolean supported = proxy != null ? true : false;
- static final boolean supportsTransparentAuth = supported ? supportsTransparentAuth(supportsTA) : false;
+ static final boolean supportsTransparentAuth = supported ? supportsTransparentAuth() : false;
private final Constructor extends AuthenticationInfo> threeArgCtr;
private final Constructor extends AuthenticationInfo> fiveArgCtr;
@@ -82,9 +84,22 @@ class NTLMAuthenticationProxy {
* authentication (try with the current users credentials before
* prompting for username and password, etc).
*/
- private static boolean supportsTransparentAuth(Method method) {
+ private static boolean supportsTransparentAuth() {
try {
- return (Boolean)method.invoke(null);
+ return (Boolean)supportsTA.invoke(null);
+ } catch (ReflectiveOperationException roe) {
+ finest(roe);
+ }
+
+ return false;
+ }
+
+ /* Transparent authentication should only be tried with a trusted
+ * site ( when running in a secure environment ).
+ */
+ public static boolean isTrustedSite(URL url) {
+ try {
+ return (Boolean)isTrustedSite.invoke(null, url);
} catch (ReflectiveOperationException roe) {
finest(roe);
}
@@ -112,6 +127,7 @@ class NTLMAuthenticationProxy {
int.class,
PasswordAuthentication.class);
supportsTA = cl.getDeclaredMethod(supportsTAStr);
+ isTrustedSite = cl.getDeclaredMethod(isTrustedSiteStr, java.net.URL.class);
return new NTLMAuthenticationProxy(threeArg,
fiveArg);
}
diff --git a/jdk/src/share/classes/org/relaxng/datatype/DatatypeException.java b/jdk/src/share/classes/sun/net/www/protocol/http/ntlm/NTLMAuthenticationCallback.java
similarity index 50%
rename from jdk/src/share/classes/org/relaxng/datatype/DatatypeException.java
rename to jdk/src/share/classes/sun/net/www/protocol/http/ntlm/NTLMAuthenticationCallback.java
index aae00d0aa0b..92886311e09 100644
--- a/jdk/src/share/classes/org/relaxng/datatype/DatatypeException.java
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/ntlm/NTLMAuthenticationCallback.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,42 +23,37 @@
* questions.
*/
-package org.relaxng.datatype;
+package sun.net.www.protocol.http.ntlm;
+
+import java.net.URL;
/**
- * Signals Datatype related exceptions.
- *
- * @author James Clark
- * @author Kohsuke KAWAGUCHI
+ * This class is used to call back to deployment to determine if a given
+ * URL is trusted. Transparent authentication (try with logged in users
+ * credentials without prompting) should only be tried with trusted sites.
*/
-public class DatatypeException extends Exception {
+public abstract class NTLMAuthenticationCallback {
+ private static volatile NTLMAuthenticationCallback callback =
+ new DefaultNTLMAuthenticationCallback();
- public DatatypeException( int index, String msg ) {
- super(msg);
- this.index = index;
- }
- public DatatypeException( String msg ) {
- this(UNKNOWN,msg);
- }
- /**
- * A constructor for those datatype libraries which don't support any
- * diagnostic information at all.
- */
- public DatatypeException() {
- this(UNKNOWN,null);
- }
+ public static void setNTLMAuthenticationCallback(
+ NTLMAuthenticationCallback callback) {
+ NTLMAuthenticationCallback.callback = callback;
+ }
+ public static NTLMAuthenticationCallback getNTLMAuthenticationCallback() {
+ return callback;
+ }
- private final int index;
+ /**
+ * Returns true if the given site is trusted, i.e. we can try
+ * transparent Authentication.
+ */
+ public abstract boolean isTrustedSite(URL url);
- public static final int UNKNOWN = -1;
-
- /**
- * Gets the index of the content where the error occured.
- * UNKNOWN can be returned to indicate that no index information
- * is available.
- */
- public int getIndex() {
- return index;
- }
+ static class DefaultNTLMAuthenticationCallback extends NTLMAuthenticationCallback {
+ @Override
+ public boolean isTrustedSite(URL url) { return true; }
+ }
}
+
diff --git a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
index 8d2e31bf74c..de712d6b64f 100644
--- a/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
+++ b/jdk/src/share/classes/sun/nio/ch/DatagramChannelImpl.java
@@ -32,6 +32,7 @@ import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.*;
+import sun.net.ResourceManager;
/**
@@ -101,14 +102,22 @@ class DatagramChannelImpl
throws IOException
{
super(sp);
- this.family = Net.isIPv6Available() ?
- StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
- this.fd = Net.socket(family, false);
- this.fdVal = IOUtil.fdVal(fd);
- this.state = ST_UNCONNECTED;
+ ResourceManager.beforeUdpCreate();
+ try {
+ this.family = Net.isIPv6Available() ?
+ StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
+ this.fd = Net.socket(family, false);
+ this.fdVal = IOUtil.fdVal(fd);
+ this.state = ST_UNCONNECTED;
+ } catch (IOException ioe) {
+ ResourceManager.afterUdpClose();
+ throw ioe;
+ }
}
- public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family) {
+ public DatagramChannelImpl(SelectorProvider sp, ProtocolFamily family)
+ throws IOException
+ {
super(sp);
if ((family != StandardProtocolFamily.INET) &&
(family != StandardProtocolFamily.INET6))
@@ -755,11 +764,14 @@ class DatagramChannelImpl
throw new IllegalArgumentException("Group not a multicast address");
// check multicast address is compatible with this socket
- if (!(group instanceof Inet4Address)) {
- if (family == StandardProtocolFamily.INET)
- throw new IllegalArgumentException("Group is not IPv4 address");
- if (!(group instanceof Inet6Address))
- throw new IllegalArgumentException("Address type not supported");
+ if (group instanceof Inet4Address) {
+ if (family == StandardProtocolFamily.INET6 && !Net.canIPv6SocketJoinIPv4Group())
+ throw new IllegalArgumentException("Group is not IPv4 multicast address");
+ } else if (group instanceof Inet6Address) {
+ if (family != StandardProtocolFamily.INET6)
+ throw new IllegalArgumentException("Group is not IPv6 multicast address");
+ } else {
+ throw new IllegalArgumentException("Address type not supported");
}
// check source address
@@ -791,7 +803,9 @@ class DatagramChannelImpl
}
MembershipKeyImpl key;
- if (family == StandardProtocolFamily.INET6) {
+ if ((family == StandardProtocolFamily.INET6) &&
+ ((group instanceof Inet6Address) || Net.canJoin6WithIPv4Group()))
+ {
int index = interf.getIndex();
if (index == -1)
throw new IOException("Network interface cannot be identified");
@@ -861,7 +875,7 @@ class DatagramChannelImpl
return;
try {
- if (family == StandardProtocolFamily.INET6) {
+ if (key instanceof MembershipKeyImpl.Type6) {
MembershipKeyImpl.Type6 key6 =
(MembershipKeyImpl.Type6)key;
Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source());
@@ -901,7 +915,7 @@ class DatagramChannelImpl
throw new IllegalArgumentException("Source address is different type to group");
int n;
- if (family == StandardProtocolFamily.INET6) {
+ if (key instanceof MembershipKeyImpl.Type6) {
MembershipKeyImpl.Type6 key6 =
(MembershipKeyImpl.Type6)key;
n = Net.block6(fd, key6.groupAddress(), key6.index(),
@@ -931,7 +945,7 @@ class DatagramChannelImpl
throw new IllegalStateException("key is no longer valid");
try {
- if (family == StandardProtocolFamily.INET6) {
+ if (key instanceof MembershipKeyImpl.Type6) {
MembershipKeyImpl.Type6 key6 =
(MembershipKeyImpl.Type6)key;
Net.unblock6(fd, key6.groupAddress(), key6.index(),
@@ -952,6 +966,7 @@ class DatagramChannelImpl
protected void implCloseSelectableChannel() throws IOException {
synchronized (stateLock) {
nd.preClose(fd);
+ ResourceManager.afterUdpClose();
// if member of mulitcast group then invalidate all keys
if (registry != null)
diff --git a/jdk/src/share/classes/sun/nio/ch/Net.java b/jdk/src/share/classes/sun/nio/ch/Net.java
index b1b893a5cb2..58cfe3b1a5b 100644
--- a/jdk/src/share/classes/sun/nio/ch/Net.java
+++ b/jdk/src/share/classes/sun/nio/ch/Net.java
@@ -60,6 +60,21 @@ class Net { // package-private
return isIPv6Available;
}
+ /**
+ * Tells whether IPv6 sockets can join IPv4 multicast groups
+ */
+ static boolean canIPv6SocketJoinIPv4Group() {
+ return canIPv6SocketJoinIPv4Group0();
+ }
+
+ /**
+ * Tells whether {@link #join6} can be used to join an IPv4
+ * multicast group (IPv4 group as IPv4-mapped IPv6 address)
+ */
+ static boolean canJoin6WithIPv4Group() {
+ return canJoin6WithIPv4Group0();
+ }
+
static InetSocketAddress checkAddress(SocketAddress sa) {
if (sa == null)
throw new NullPointerException();
@@ -291,13 +306,18 @@ class Net { // package-private
// -- Socket operations --
- static native boolean isIPv6Available0();
+ private static native boolean isIPv6Available0();
- static FileDescriptor socket(boolean stream) {
+ private static native boolean canIPv6SocketJoinIPv4Group0();
+
+ private static native boolean canJoin6WithIPv4Group0();
+
+ static FileDescriptor socket(boolean stream) throws IOException {
return socket(UNSPEC, stream);
}
- static FileDescriptor socket(ProtocolFamily family, boolean stream) {
+ static FileDescriptor socket(ProtocolFamily family, boolean stream)
+ throws IOException {
boolean preferIPv6 = isIPv6Available() &&
(family != StandardProtocolFamily.INET);
return IOUtil.newFD(socket0(preferIPv6, stream, false));
diff --git a/jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java b/jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java
index 4011291d009..07f931c995c 100644
--- a/jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java
+++ b/jdk/src/share/classes/sun/nio/cs/ext/ExtendedCharsets.java
@@ -679,6 +679,14 @@ public class ExtendedCharsets
"1124"
});
+ charset("x-IBM1364", "IBM1364",
+ new String[] {
+ "cp1364",
+ "ibm1364",
+ "ibm-1364",
+ "1364"
+ });
+
charset("IBM273", "IBM273",
new String[] {
"cp273", // JDK historical
diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java b/jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java
index cd1e6c26b8d..33eeb315f43 100644
--- a/jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractAclFileAttributeView.java
@@ -57,8 +57,8 @@ abstract class AbstractAclFileAttributeView
setAcl((List)value);
return;
}
- throw new UnsupportedOperationException("'" + name() + ":" +
- attribute + "' not supported");
+ throw new IllegalArgumentException("'" + name() + ":" +
+ attribute + "' not recognized");
}
@Override
@@ -81,6 +81,8 @@ abstract class AbstractAclFileAttributeView
owner = true;
continue;
}
+ throw new IllegalArgumentException("'" + name() + ":" +
+ attribute + "' not recognized");
}
Map result = new HashMap<>(2);
if (acl)
diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java b/jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java
index 6383c08edf1..9fa04ee7f8e 100644
--- a/jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractBasicFileAttributeView.java
@@ -46,6 +46,18 @@ abstract class AbstractBasicFileAttributeView
private static final String IS_SYMBOLIC_LINK_NAME = "isSymbolicLink";
private static final String IS_OTHER_NAME = "isOther";
+ // the names of the basic attributes
+ static final Set basicAttributeNames =
+ Util.newSet(SIZE_NAME,
+ CREATION_TIME_NAME,
+ LAST_ACCESS_TIME_NAME,
+ LAST_MODIFIED_TIME_NAME,
+ FILE_KEY_NAME,
+ IS_DIRECTORY_NAME,
+ IS_REGULAR_FILE_NAME,
+ IS_SYMBOLIC_LINK_NAME,
+ IS_OTHER_NAME);
+
protected AbstractBasicFileAttributeView() { }
@Override
@@ -69,24 +81,26 @@ abstract class AbstractBasicFileAttributeView
setTimes(null, null, (FileTime)value);
return;
}
- throw new UnsupportedOperationException("'" + attribute +
- "' is unknown or read-only attribute");
+ throw new IllegalArgumentException("'" + name() + ":" +
+ attribute + "' not recognized");
}
/**
* Used to build a map of attribute name/values.
*/
static class AttributesBuilder {
- private Set set = new HashSet<>();
+ private Set names = new HashSet<>();
private Map map = new HashMap<>();
private boolean copyAll;
- private AttributesBuilder(String[] attributes) {
- for (String attribute: attributes) {
- if (attribute.equals("*")) {
+ private AttributesBuilder(Set allowed, String[] requested) {
+ for (String name: requested) {
+ if (name.equals("*")) {
copyAll = true;
} else {
- set.add(attribute);
+ if (!allowed.contains(name))
+ throw new IllegalArgumentException("'" + name + "' not recognized");
+ names.add(name);
}
}
}
@@ -94,21 +108,19 @@ abstract class AbstractBasicFileAttributeView
/**
* Creates builder to build up a map of the matching attributes
*/
- static AttributesBuilder create(String[] attributes) {
- return new AttributesBuilder(attributes);
+ static AttributesBuilder create(Set allowed, String[] requested) {
+ return new AttributesBuilder(allowed, requested);
}
/**
* Returns true if the attribute should be returned in the map
*/
- boolean match(String attribute) {
- if (copyAll)
- return true;
- return set.contains(attribute);
+ boolean match(String name) {
+ return copyAll || names.contains(name);
}
- void add(String attribute, Object value) {
- map.put(attribute, value);
+ void add(String name, Object value) {
+ map.put(name, value);
}
/**
@@ -124,7 +136,7 @@ abstract class AbstractBasicFileAttributeView
* Invoked by readAttributes or sub-classes to add all matching basic
* attributes to the builder
*/
- final void addBasicAttributesToBuilder(BasicFileAttributes attrs,
+ final void addRequestedBasicAttributes(BasicFileAttributes attrs,
AttributesBuilder builder)
{
if (builder.match(SIZE_NAME))
@@ -148,9 +160,12 @@ abstract class AbstractBasicFileAttributeView
}
@Override
- public Map readAttributes(String[] attributes) throws IOException {
- AttributesBuilder builder = AttributesBuilder.create(attributes);
- addBasicAttributesToBuilder(readAttributes(), builder);
+ public Map readAttributes(String[] requested)
+ throws IOException
+ {
+ AttributesBuilder builder =
+ AttributesBuilder.create(basicAttributeNames, requested);
+ addRequestedBasicAttributes(readAttributes(), builder);
return builder.unmodifiableMap();
}
}
diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractFileSystemProvider.java b/jdk/src/share/classes/sun/nio/fs/AbstractFileSystemProvider.java
index 95d1cb30931..9e1dc6133ac 100644
--- a/jdk/src/share/classes/sun/nio/fs/AbstractFileSystemProvider.java
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractFileSystemProvider.java
@@ -29,7 +29,6 @@ import java.nio.file.*;
import java.nio.file.spi.FileSystemProvider;
import java.io.IOException;
import java.util.Map;
-import java.util.Collections;
/**
* Base implementation class of FileSystemProvider
@@ -72,6 +71,8 @@ abstract class AbstractFileSystemProvider extends FileSystemProvider {
throws IOException
{
String[] s = split(attribute);
+ if (s[0].length() == 0)
+ throw new IllegalArgumentException(attribute);
DynamicFileAttributeView view = getFileAttributeView(file, s[0], options);
if (view == null)
throw new UnsupportedOperationException("View '" + s[0] + "' not available");
@@ -83,9 +84,11 @@ abstract class AbstractFileSystemProvider extends FileSystemProvider {
throws IOException
{
String[] s = split(attributes);
+ if (s[0].length() == 0)
+ throw new IllegalArgumentException(attributes);
DynamicFileAttributeView view = getFileAttributeView(file, s[0], options);
if (view == null)
- return Collections.emptyMap();
+ throw new UnsupportedOperationException("View '" + s[0] + "' not available");
return view.readAttributes(s[1].split(","));
}
diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java b/jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java
index cf36a09ff0a..8a4f975c4f4 100644
--- a/jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractUserDefinedFileAttributeView.java
@@ -59,22 +59,6 @@ abstract class AbstractUserDefinedFileAttributeView
return "user";
}
- private Object getAttribute(String attribute) throws IOException {
- int size;
- try {
- size = size(attribute);
- } catch (IOException e) {
- // not found or some other I/O error
- if (list().contains(attribute))
- throw e;
- return null;
- }
-
- byte[] buf = new byte[size];
- int n = read(attribute, ByteBuffer.wrap(buf));
- return (n == size) ? buf : Arrays.copyOf(buf, n);
- }
-
@Override
public final void setAttribute(String attribute, Object value)
throws IOException
@@ -94,12 +78,13 @@ abstract class AbstractUserDefinedFileAttributeView
{
// names of attributes to return
List names = new ArrayList<>();
-
for (String name: attributes) {
if (name.equals("*")) {
names = list();
break;
} else {
+ if (name.length() == 0)
+ throw new IllegalArgumentException();
names.add(name);
}
}
@@ -107,11 +92,12 @@ abstract class AbstractUserDefinedFileAttributeView
// read each value and return in map
Map result = new HashMap<>();
for (String name: names) {
- Object value = getAttribute(name);
- if (value != null)
- result.put(name, value);
+ int size = size(name);
+ byte[] buf = new byte[size];
+ int n = read(name, ByteBuffer.wrap(buf));
+ byte[] value = (n == size) ? buf : Arrays.copyOf(buf, n);
+ result.put(name, value);
}
-
return result;
}
}
diff --git a/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java b/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java
index 55234ba6528..f083f46313a 100644
--- a/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java
+++ b/jdk/src/share/classes/sun/nio/fs/AbstractWatchKey.java
@@ -81,7 +81,8 @@ abstract class AbstractWatchKey implements WatchKey {
/**
* Return the original watchable (Path)
*/
- Path watchable() {
+ @Override
+ public Path watchable() {
return dir;
}
diff --git a/jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java b/jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java
index aae9bd318c1..5fcb21e264a 100644
--- a/jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java
+++ b/jdk/src/share/classes/sun/nio/fs/FileOwnerAttributeViewImpl.java
@@ -63,10 +63,10 @@ final class FileOwnerAttributeViewImpl
{
if (attribute.equals(OWNER_NAME)) {
setOwner((UserPrincipal)value);
- return;
+ } else {
+ throw new IllegalArgumentException("'" + name() + ":" +
+ attribute + "' not recognized");
}
- throw new UnsupportedOperationException("'" + name() + ":" +
- attribute + "' not supported");
}
@Override
@@ -75,6 +75,9 @@ final class FileOwnerAttributeViewImpl
for (String attribute: attributes) {
if (attribute.equals("*") || attribute.equals(OWNER_NAME)) {
result.put(OWNER_NAME, getOwner());
+ } else {
+ throw new IllegalArgumentException("'" + name() + ":" +
+ attribute + "' not recognized");
}
}
return result;
diff --git a/jdk/src/share/classes/sun/nio/fs/Util.java b/jdk/src/share/classes/sun/nio/fs/Util.java
index 6a289058e4b..76287011169 100644
--- a/jdk/src/share/classes/sun/nio/fs/Util.java
+++ b/jdk/src/share/classes/sun/nio/fs/Util.java
@@ -25,6 +25,8 @@
package sun.nio.fs;
+import java.util.*;
+
/**
* Utility methods
*/
@@ -54,6 +56,28 @@ class Util {
}
result[n] = s.substring(last, s.length());
return result;
+ }
+ /**
+ * Returns a Set containing the given elements.
+ */
+ static Set newSet(E... elements) {
+ HashSet set = new HashSet<>();
+ for (E e: elements) {
+ set.add(e);
+ }
+ return set;
+ }
+
+ /**
+ * Returns a Set containing all the elements of the given Set plus
+ * the given elements.
+ */
+ static Set newSet(Set other, E... elements) {
+ HashSet set = new HashSet<>(other);
+ for (E e: elements) {
+ set.add(e);
+ }
+ return set;
}
}
diff --git a/jdk/src/share/classes/sun/security/pkcs11/P11Key.java b/jdk/src/share/classes/sun/security/pkcs11/P11Key.java
index b54d0d3c190..56c40a97586 100644
--- a/jdk/src/share/classes/sun/security/pkcs11/P11Key.java
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11Key.java
@@ -999,18 +999,34 @@ abstract class P11Key implements Key {
new CK_ATTRIBUTE(CKA_EC_PARAMS),
};
fetchAttributes(attributes);
+
try {
params = P11ECKeyFactory.decodeParameters
(attributes[1].getByteArray());
- DerValue wECPoint = new DerValue(attributes[0].getByteArray());
- if (wECPoint.getTag() != DerValue.tag_OctetString)
- throw new IOException("Unexpected tag: " +
- wECPoint.getTag());
- params = P11ECKeyFactory.decodeParameters
- (attributes[1].getByteArray());
- w = P11ECKeyFactory.decodePoint
- (wECPoint.getDataBytes(), params.getCurve());
+ /*
+ * An uncompressed EC point may be in either of two formats.
+ * First try the OCTET STRING encoding:
+ * 04 04
+ *
+ * Otherwise try the raw encoding:
+ * 04
+ */
+ byte[] ecKey = attributes[0].getByteArray();
+
+ try {
+ DerValue wECPoint = new DerValue(ecKey);
+ if (wECPoint.getTag() != DerValue.tag_OctetString)
+ throw new IOException("Unexpected tag: " +
+ wECPoint.getTag());
+
+ w = P11ECKeyFactory.decodePoint
+ (wECPoint.getDataBytes(), params.getCurve());
+
+ } catch (IOException e) {
+ // Failover
+ w = P11ECKeyFactory.decodePoint(ecKey, params.getCurve());
+ }
} catch (Exception e) {
throw new RuntimeException("Could not parse key values", e);
diff --git a/jdk/src/share/classes/sun/security/provider/certpath/AdaptableX509CertSelector.java b/jdk/src/share/classes/sun/security/provider/certpath/AdaptableX509CertSelector.java
index 1b14bf8fa66..959ac59d12c 100644
--- a/jdk/src/share/classes/sun/security/provider/certpath/AdaptableX509CertSelector.java
+++ b/jdk/src/share/classes/sun/security/provider/certpath/AdaptableX509CertSelector.java
@@ -46,10 +46,16 @@ import sun.security.x509.AuthorityKeyIdentifierExtension;
*/
class AdaptableX509CertSelector extends X509CertSelector {
// The start date of a validity period.
- private Date startDate = null;
+ private Date startDate;
// The end date of a validity period.
- private Date endDate = null;
+ private Date endDate;
+
+ // Is subject key identifier sensitive?
+ private boolean isSKIDSensitive = false;
+
+ // Is serial number sensitive?
+ private boolean isSNSensitive = false;
AdaptableX509CertSelector() {
super();
@@ -97,15 +103,24 @@ class AdaptableX509CertSelector extends X509CertSelector {
if (akidext != null) {
KeyIdentifier akid = (KeyIdentifier)akidext.get(akidext.KEY_ID);
if (akid != null) {
- DerOutputStream derout = new DerOutputStream();
- derout.putOctetString(akid.getIdentifier());
- super.setSubjectKeyIdentifier(derout.toByteArray());
+ // Do not override the previous setting for initial selection.
+ if (isSKIDSensitive || getSubjectKeyIdentifier() == null) {
+ DerOutputStream derout = new DerOutputStream();
+ derout.putOctetString(akid.getIdentifier());
+ super.setSubjectKeyIdentifier(derout.toByteArray());
+
+ isSKIDSensitive = true;
+ }
}
SerialNumber asn =
(SerialNumber)akidext.get(akidext.SERIAL_NUMBER);
if (asn != null) {
- super.setSerialNumber(asn.getNumber());
+ // Do not override the previous setting for initial selection.
+ if (isSNSensitive || getSerialNumber() == null) {
+ super.setSerialNumber(asn.getNumber());
+ isSNSensitive = true;
+ }
}
// the subject criterion should be set by the caller.
@@ -148,11 +163,25 @@ class AdaptableX509CertSelector extends X509CertSelector {
}
}
- if (version < 3 || xcert.getExtensionValue("2.5.29.14") == null) {
- // If no SubjectKeyIdentifier extension, don't bother to check it.
+ // If no SubjectKeyIdentifier extension, don't bother to check it.
+ if (isSKIDSensitive &&
+ (version < 3 || xcert.getExtensionValue("2.5.29.14") == null)) {
setSubjectKeyIdentifier(null);
}
+ // In practice, a CA may replace its root certificate and require that
+ // the existing certificate is still valid, even if the AKID extension
+ // does not match the replacement root certificate fields.
+ //
+ // Conservatively, we only support the replacement for version 1 and
+ // version 2 certificate. As for version 2, the certificate extension
+ // may contain sensitive information (for example, policies), the
+ // AKID need to be respected to seek the exact certificate in case
+ // of key or certificate abuse.
+ if (isSNSensitive && version < 3) {
+ setSerialNumber(null);
+ }
+
return super.match(cert);
}
diff --git a/jdk/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/jdk/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java
index e9c0ca77879..e2666a6771b 100644
--- a/jdk/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java
+++ b/jdk/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java
@@ -243,12 +243,6 @@ class ForwardBuilder extends Builder {
caTargetSelector.setPolicy(getMatchingPolicies());
}
- /*
- * Require CA certs with a pathLenConstraint that allows
- * at least as many CA certs that have already been traversed
- */
- caTargetSelector.setBasicConstraints(currentState.traversedCACerts);
-
sel = caTargetSelector;
} else {
@@ -282,12 +276,6 @@ class ForwardBuilder extends Builder {
CertPathHelper.setPathToNames
(caSelector, currentState.subjectNamesTraversed);
- /*
- * Require CA certs with a pathLenConstraint that allows
- * at least as many CA certs that have already been traversed
- */
- caSelector.setBasicConstraints(currentState.traversedCACerts);
-
/*
* Facilitate certification path construction with authority
* key identifier and subject key identifier.
@@ -305,6 +293,14 @@ class ForwardBuilder extends Builder {
sel = caSelector;
}
+ /*
+ * For compatibility, conservatively, we don't check the path
+ * length constraint of trusted anchors. Please don't set the
+ * basic constraints criterion unless the trusted certificate
+ * matching is completed.
+ */
+ sel.setBasicConstraints(-1);
+
for (X509Certificate trustedCert : trustedCerts) {
if (sel.match(trustedCert)) {
if (debug != null) {
@@ -323,6 +319,12 @@ class ForwardBuilder extends Builder {
*/
sel.setCertificateValid(date);
+ /*
+ * Require CA certs with a pathLenConstraint that allows
+ * at least as many CA certs that have already been traversed
+ */
+ sel.setBasicConstraints(currentState.traversedCACerts);
+
/*
* If we have already traversed as many CA certs as the maxPathLength
* will allow us to, then we don't bother looking through these
diff --git a/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java
index 3920b35c37a..fbf23196aba 100644
--- a/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java
+++ b/jdk/src/share/classes/sun/security/ssl/ClientHandshaker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2011, 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
@@ -377,8 +377,9 @@ final class ClientHandshaker extends Handshaker {
ProtocolVersion mesgVersion = mesg.protocolVersion;
if (!isNegotiable(mesgVersion)) {
throw new SSLHandshakeException(
- "Server chose unsupported or disabled protocol: " +
- mesgVersion);
+ "Server chose " + mesgVersion +
+ ", but that protocol version is not enabled or not supported " +
+ "by the client.");
}
handshakeHash.protocolDetermined(mesgVersion);
diff --git a/jdk/src/share/classes/sun/security/ssl/SunJSSE.java b/jdk/src/share/classes/sun/security/ssl/SunJSSE.java
index 1668e6ff79d..bba258670d8 100644
--- a/jdk/src/share/classes/sun/security/ssl/SunJSSE.java
+++ b/jdk/src/share/classes/sun/security/ssl/SunJSSE.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2011, 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
@@ -195,6 +195,8 @@ public abstract class SunJSSE extends java.security.Provider {
"sun.security.ssl.KeyManagerFactoryImpl$SunX509");
put("KeyManagerFactory.NewSunX509",
"sun.security.ssl.KeyManagerFactoryImpl$X509");
+ put("Alg.Alias.KeyManagerFactory.PKIX", "NewSunX509");
+
put("TrustManagerFactory.SunX509",
"sun.security.ssl.TrustManagerFactoryImpl$SimpleFactory");
put("TrustManagerFactory.PKIX",
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java
index a5c73549809..0016ae24d20 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java
@@ -216,6 +216,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"Pierre & Miquelon Standard Time", "PMST",
"Pierre & Miquelon Daylight Time", "PMDT"}},
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java
index b3cb23224fa..0e4d91d94f7 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_de.java
@@ -216,6 +216,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"Pierre & Miquelon Normalzeit", "PMST",
"Pierre & Miquelon Sommerzeit", "PMDT"}},
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java
index 613cc6419fb..711afc45563 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_es.java
@@ -216,6 +216,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"Hora est\u00e1ndar de Pierre & Miquelon", "PMST",
"Hora de verano de Pierre & Miquelon", "PMDT"}},
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java
index f1dc5300c25..090820b6742 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_fr.java
@@ -216,6 +216,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"Heure normale de Saint-Pierre et Miquelon", "PMST",
"Heure avanc\u00e9e de Saint-Pierre et Miquelon", "PMDT"}},
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java
index e983872e7a1..6413104ba74 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_it.java
@@ -216,6 +216,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"Ora solare di Saint-Pierre e Miquelon", "PMST",
"Ora legale di Saint-Pierre e Miquelon", "PMDT"}},
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java
index 56330acf91d..4c1226666c8 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ja.java
@@ -216,6 +216,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"\u30b5\u30f3\u30d4\u30a8\u30fc\u30eb\u30fb\u30df\u30af\u30ed\u30f3\u8af8\u5cf6\u6a19\u6e96\u6642", "PMST",
"\u30b5\u30f3\u30d4\u30a8\u30fc\u30eb\u30fb\u30df\u30af\u30ed\u30f3\u8af8\u5cf6\u590f\u6642\u9593", "PMDT"}},
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java
index 82edcce1ec5..486e1bdd9a5 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_ko.java
@@ -216,6 +216,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"\ud53c\uc5d0\ub974 \ubbf8\ud06c\ub860 \ud45c\uc900\uc2dc", "PMST",
"\ud53c\uc5d0\ub974 \ubbf8\ud06c\ub860 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "PMDT"}},
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_pt_BR.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_pt_BR.java
index d9b83fe0491..7eab4bb48b4 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_pt_BR.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_pt_BR.java
@@ -217,6 +217,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"Fuso hor\u00e1rio padr\u00e3o de S\u00e3o Pedro e Miquelon", "PMST",
"Hor\u00e1rio de luz natural de S\u00e3o Pedro e Miquelon", "PMDT"}},
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java
index 14108065241..63b5e084523 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_sv.java
@@ -216,6 +216,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"Saint-Pierre-et-Miquelon, normaltid", "PMST",
"Saint-Pierre-et-Miquelon, sommartid", "PMDT"}},
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java
index 4f80a1b739c..b215a186e9a 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_CN.java
@@ -216,6 +216,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"\u76ae\u57c3\u5c14\u5c9b\u53ca\u5bc6\u514b\u9686\u5c9b\u6807\u51c6\u65f6\u95f4", "PMST",
"\u76ae\u57c3\u5c14\u5c9b\u53ca\u5bc6\u514b\u9686\u5c9b\u590f\u4ee4\u65f6", "PMDT"}},
diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java
index 5218bed7ed6..7a638641e89 100644
--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java
+++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames_zh_TW.java
@@ -216,6 +216,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle {
{"America/Anchorage", AKST},
{"AST", AKST},
{"America/Halifax", AST},
+ {"America/Sitka", AKST},
{"America/St_Johns", NST},
{"CNT", NST},
{"Europe/Paris", CET},
@@ -392,6 +393,8 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle {
{"America/Mendoza", AGT},
{"America/Menominee", CST},
{"America/Merida", CST},
+ {"America/Metlakatla", new String[] {"Metlakatla Standard Time", "MeST",
+ "Metlakatla Daylight Time", "MeDT"}},
{"America/Mexico_City", CST},
{"America/Miquelon", new String[] {"\u76ae\u57c3\u723e\u5cf6\u53ca\u5bc6\u514b\u9686\u5cf6\u6a19\u6e96\u6642\u9593", "PMST",
"\u76ae\u57c3\u723e\u5cf6\u53ca\u5bc6\u514b\u9686\u5cf6\u65e5\u5149\u7bc0\u7d04\u6642\u9593", "PMDT"}},
diff --git a/jdk/src/share/lib/security/java.security b/jdk/src/share/lib/security/java.security
index 5a0726de0a7..a89d40e194b 100644
--- a/jdk/src/share/lib/security/java.security
+++ b/jdk/src/share/lib/security/java.security
@@ -123,7 +123,7 @@ keystore.type=jks
# passed to checkPackageAccess unless the
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
-package.access=sun.,com.sun.imageio.
+package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.
#
# List of comma-separated packages that start with or equal this string
diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris
index 8e9b1ffd791..1a19f44d231 100644
--- a/jdk/src/share/lib/security/java.security-solaris
+++ b/jdk/src/share/lib/security/java.security-solaris
@@ -124,7 +124,7 @@ keystore.type=jks
# passed to checkPackageAccess unless the
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
-package.access=sun.,com.sun.imageio.
+package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.
#
# List of comma-separated packages that start with or equal this string
diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows
index 99eda51b910..3db627a4f32 100644
--- a/jdk/src/share/lib/security/java.security-windows
+++ b/jdk/src/share/lib/security/java.security-windows
@@ -124,7 +124,7 @@ keystore.type=jks
# passed to checkPackageAccess unless the
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
-package.access=sun.,com.sun.imageio.
+package.access=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.
#
# List of comma-separated packages that start with or equal this string
diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
index b53b14ed87b..40067b1df0f 100644
--- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
+++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp
@@ -489,7 +489,6 @@ enum { CHUNK = (1 << 14), SMALL = (1 << 9) };
// Call malloc. Try to combine small blocks and free much later.
void* unpacker::alloc_heap(size_t size, bool smallOK, bool temp) {
- CHECK_0;
if (!smallOK || size > SMALL) {
void* res = must_malloc((int)size);
(temp ? &tmallocs : &mallocs)->add(res);
@@ -2560,6 +2559,10 @@ void unpacker::putlayout(band** body) {
int i;
int prevBII = -1;
int prevBCI = -1;
+ if (body == NULL) {
+ abort("putlayout: unexpected NULL for body");
+ return;
+ }
for (i = 0; body[i] != null; i++) {
band& b = *body[i];
byte le_kind = b.le_kind;
@@ -4767,7 +4770,9 @@ void unpacker::redirect_stdio() {
}
char *tname = tempnam(tmpdir,"#upkg");
+ if (tname == NULL) return;
sprintf(log_file_name, "%s", tname);
+ ::free(tname);
if ((errstrm = fopen(log_file_name, "a+")) != NULL) {
log_file = errstrm_name = saveStr(log_file_name);
return ;
diff --git a/jdk/src/share/native/com/sun/media/sound/SoundDefs.h b/jdk/src/share/native/com/sun/media/sound/SoundDefs.h
index 5ac73451681..f141ea62ac2 100644
--- a/jdk/src/share/native/com/sun/media/sound/SoundDefs.h
+++ b/jdk/src/share/native/com/sun/media/sound/SoundDefs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2011, 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
@@ -39,6 +39,8 @@
#define X_IA64 4
#define X_AMD64 5
#define X_ZERO 6
+#define X_ARM 7
+#define X_PPC 8
// **********************************
// Make sure you set X_PLATFORM and X_ARCH defines correctly.
diff --git a/jdk/src/share/native/common/check_code.c b/jdk/src/share/native/common/check_code.c
index 00dcdf163b3..dcdaeda58bf 100644
--- a/jdk/src/share/native/common/check_code.c
+++ b/jdk/src/share/native/common/check_code.c
@@ -2685,11 +2685,11 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta
switch (type_table[operand]) {
case JVM_CONSTANT_MethodType:
full_info = make_class_info_from_name(context,
- "java/dyn/MethodType");
+ "java/lang/invoke/MethodType");
break;
default: //JVM_CONSTANT_MethodHandle
full_info = make_class_info_from_name(context,
- "java/dyn/MethodHandle");
+ "java/lang/invoke/MethodHandle");
break;
}
break;
diff --git a/jdk/src/share/native/java/lang/fdlibm/include/fdlibm.h b/jdk/src/share/native/java/lang/fdlibm/include/fdlibm.h
index 2b3592dc143..196bb0d8e02 100644
--- a/jdk/src/share/native/java/lang/fdlibm/include/fdlibm.h
+++ b/jdk/src/share/native/java/lang/fdlibm/include/fdlibm.h
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,8 +28,8 @@
#ifdef __NEWVALID /* special setup for Sun test regime */
#if defined(i386) || defined(i486) || \
- defined(intel) || defined(x86) || \
- defined(i86pc) || defined(_M_IA64) || defined(ia64)
+ defined(intel) || defined(x86) || defined(arm) || \
+ defined(i86pc) || defined(_M_IA64) || defined(ia64)
#define _LITTLE_ENDIAN
#endif
#endif
diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c
index 04a87fd1cac..84b91889725 100644
--- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c
+++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c
@@ -40,7 +40,7 @@
#include
#include
#include
-
+#include
/* java native interface headers */
#include "jni.h"
@@ -2657,7 +2657,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage
(destWidth < 0) || (destWidth > srcWidth) ||
(destHeight < 0) ||
(stepX < 0) || (stepY < 0) ||
- ((scanLineSize / numBands) < destWidth)) /* destWidth causes an integer overflow */
+ ((INT_MAX / numBands) < destWidth)) /* destWidth causes an integer overflow */
{
JNU_ThrowByName(env, "javax/imageio/IIOException",
"Invalid argument to native writeImage");
diff --git a/jdk/src/share/native/sun/font/layout/KernTable.cpp b/jdk/src/share/native/sun/font/layout/KernTable.cpp
index 8d368211309..3a9987eb6b9 100644
--- a/jdk/src/share/native/sun/font/layout/KernTable.cpp
+++ b/jdk/src/share/native/sun/font/layout/KernTable.cpp
@@ -210,7 +210,7 @@ void KernTable::process(LEGlyphStorage& storage)
// all the elements ahead of time and store them in the font
const PairInfo* p = pairs;
- const PairInfo* tp = (const PairInfo*)(p + rangeShift);
+ const PairInfo* tp = (const PairInfo*)(p + (rangeShift/KERN_PAIRINFO_SIZE)); /* rangeshift is in original table bytes */
if (key > tp->key) {
p = tp;
}
@@ -222,7 +222,7 @@ void KernTable::process(LEGlyphStorage& storage)
le_uint32 probe = searchRange;
while (probe > 1) {
probe >>= 1;
- tp = (const PairInfo*)(p + probe);
+ tp = (const PairInfo*)(p + (probe/KERN_PAIRINFO_SIZE));
le_uint32 tkey = tp->key;
#if DEBUG
fprintf(stdout, " %.3d (%0.8x)\n", (tp - pairs), tkey);
diff --git a/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp
index 6b0aa1baa58..90aafde2a80 100644
--- a/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp
+++ b/jdk/src/share/native/sun/font/layout/LayoutEngine.cpp
@@ -251,6 +251,10 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off
return 0;
}
+ if ((fTypoFlags & 0x4) == 0) { // no canonical processing
+ return count;
+ }
+
const GlyphSubstitutionTableHeader *canonGSUBTable = (GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
LETag scriptTag = OpenTypeLayoutEngine::getScriptTag(fScriptCode);
LETag langSysTag = OpenTypeLayoutEngine::getLangSysTag(fLanguageCode);
diff --git a/jdk/src/share/native/sun/java2d/loops/ProcessPath.c b/jdk/src/share/native/sun/java2d/loops/ProcessPath.c
index b4f724752dc..5131a3e22c7 100644
--- a/jdk/src/share/native/sun/java2d/loops/ProcessPath.c
+++ b/jdk/src/share/native/sun/java2d/loops/ProcessPath.c
@@ -118,19 +118,25 @@
jint Y1 = (fY1) >> MDP_PREC; \
jint res; \
\
- /* Checking bounds and clipping if necessary */ \
+ /* Checking bounds and clipping if necessary. \
+ * REMIND: It's temporary solution to avoid OOB in rendering code. \
+ * Current approach uses float equations which are unreliable for \
+ * clipping and makes assumptions about the line biases of the \
+ * rendering algorithm. Also, clipping code should be moved down \
+ * into only those output renderers that need it. \
+ */ \
if (checkBounds) { \
- TESTANDCLIP(hnd->dhnd->yMin, hnd->dhnd->yMax, Y0, X0, Y1, X1, \
- jint, res); \
+ jfloat xMinf = hnd->dhnd->xMinf + 0.5f; \
+ jfloat yMinf = hnd->dhnd->yMinf + 0.5f; \
+ jfloat xMaxf = hnd->dhnd->xMaxf + 0.5f; \
+ jfloat yMaxf = hnd->dhnd->yMaxf + 0.5f; \
+ TESTANDCLIP(yMinf, yMaxf, Y0, X0, Y1, X1, jint, res); \
if (res == CRES_INVISIBLE) break; \
- TESTANDCLIP(hnd->dhnd->yMin, hnd->dhnd->yMax, Y1, X1, Y0, X0, \
- jint, res); \
+ TESTANDCLIP(yMinf, yMaxf, Y1, X1, Y0, X0, jint, res); \
if (res == CRES_INVISIBLE) break; \
- TESTANDCLIP(hnd->dhnd->xMin, hnd->dhnd->xMax, X0, Y0, X1, Y1, \
- jint, res); \
+ TESTANDCLIP(xMinf, xMaxf, X0, Y0, X1, Y1, jint, res); \
if (res == CRES_INVISIBLE) break; \
- TESTANDCLIP(hnd->dhnd->xMin, hnd->dhnd->xMax, X1, Y1, X0, Y0, \
- jint, res); \
+ TESTANDCLIP(xMinf, xMaxf, X1, Y1, X0, Y0, jint, res); \
if (res == CRES_INVISIBLE) break; \
} \
\
diff --git a/jdk/src/share/sample/nio/file/WatchDir.java b/jdk/src/share/sample/nio/file/WatchDir.java
index 33c15dd0c04..796b728206b 100644
--- a/jdk/src/share/sample/nio/file/WatchDir.java
+++ b/jdk/src/share/sample/nio/file/WatchDir.java
@@ -33,8 +33,7 @@ import java.nio.file.*;
import static java.nio.file.StandardWatchEventKind.*;
import static java.nio.file.LinkOption.*;
import java.nio.file.attribute.*;
-import java.io.*;
-import java.util.*;
+import java.io.IOException;
/**
* Example to watch a directory (or tree) for changes to files.
@@ -43,9 +42,9 @@ import java.util.*;
public class WatchDir {
private final WatchService watcher;
- private final Map keys;
private final boolean recursive;
private boolean trace = false;
+ private int count;
@SuppressWarnings("unchecked")
static WatchEvent cast(WatchEvent> event) {
@@ -57,17 +56,9 @@ public class WatchDir {
*/
private void register(Path dir) throws IOException {
WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
- if (trace) {
- Path prev = keys.get(key);
- if (prev == null) {
- System.out.format("register: %s\n", dir);
- } else {
- if (!dir.equals(prev)) {
- System.out.format("update: %s -> %s\n", prev, dir);
- }
- }
- }
- keys.put(key, dir);
+ count++;
+ if (trace)
+ System.out.format("register: %s\n", dir);
}
/**
@@ -92,7 +83,6 @@ public class WatchDir {
*/
WatchDir(Path dir, boolean recursive) throws IOException {
this.watcher = FileSystems.getDefault().newWatchService();
- this.keys = new HashMap();
this.recursive = recursive;
if (recursive) {
@@ -121,12 +111,6 @@ public class WatchDir {
return;
}
- Path dir = keys.get(key);
- if (dir == null) {
- System.err.println("WatchKey not recognized!!");
- continue;
- }
-
for (WatchEvent> event: key.pollEvents()) {
WatchEvent.Kind kind = event.kind();
@@ -138,7 +122,7 @@ public class WatchDir {
// Context for directory entry event is the file name of entry
WatchEvent ev = cast(event);
Path name = ev.context();
- Path child = dir.resolve(name);
+ Path child = ((Path)key.watchable()).resolve(name);
// print out event
System.out.format("%s: %s\n", event.kind().name(), child);
@@ -156,15 +140,13 @@ public class WatchDir {
}
}
- // reset key and remove from set if directory no longer accessible
+ // reset key
boolean valid = key.reset();
if (!valid) {
- keys.remove(key);
-
- // all directories are inaccessible
- if (keys.isEmpty()) {
+ // directory no longer accessible
+ count--;
+ if (count == 0)
break;
- }
}
}
}
diff --git a/jdk/src/solaris/bin/ergo.c b/jdk/src/solaris/bin/ergo.c
index e9e863e9ce5..2047087e7c5 100644
--- a/jdk/src/solaris/bin/ergo.c
+++ b/jdk/src/solaris/bin/ergo.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2011, 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
@@ -67,6 +67,35 @@ ServerClassMachine(void) {
}
}
+#ifdef USE_GENERIC_ERGO
+/* Ask the OS how many processors there are. */
+static unsigned long
+physical_processors(void) {
+ const unsigned long sys_processors = sysconf(_SC_NPROCESSORS_CONF);
+ JLI_TraceLauncher("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors);
+ return sys_processors;
+}
+
+jboolean
+ServerClassMachineImpl(void) {
+ jboolean result = JNI_FALSE;
+ /* How big is a server class machine? */
+ const unsigned long server_processors = 2UL;
+ const uint64_t server_memory = 2UL * GB;
+ const uint64_t actual_memory = physical_memory();
+
+ /* Is this a server class machine? */
+ if (actual_memory >= server_memory) {
+ const unsigned long actual_processors = physical_processors();
+ if (actual_processors >= server_processors) {
+ result = JNI_TRUE;
+ }
+ }
+ JLI_TraceLauncher("unix_" LIBARCHNAME "_ServerClassMachine: %s\n",
+ (result == JNI_TRUE ? "JNI_TRUE" : "JNI_FALSE"));
+ return result;
+}
+#endif
/* Compute physical memory by asking the OS */
uint64_t
diff --git a/jdk/src/solaris/bin/ergo_sparc.c b/jdk/src/solaris/bin/ergo_sparc.c
deleted file mode 100644
index 9261a423de6..00000000000
--- a/jdk/src/solaris/bin/ergo_sparc.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 1998, 2007, 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 "ergo.h"
-
-
-/* Methods for solaris-sparc and linux-sparc: these are easy. */
-
-/* Ask the OS how many processors there are. */
-static unsigned long
-physical_processors(void) {
- const unsigned long sys_processors = sysconf(_SC_NPROCESSORS_CONF);
-
- JLI_TraceLauncher("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors);
- return sys_processors;
-}
-
-/* The sparc version of the "server-class" predicate. */
-jboolean
-ServerClassMachineImpl(void) {
- jboolean result = JNI_FALSE;
- /* How big is a server class machine? */
- const unsigned long server_processors = 2UL;
- const uint64_t server_memory = 2UL * GB;
- const uint64_t actual_memory = physical_memory();
-
- /* Is this a server class machine? */
- if (actual_memory >= server_memory) {
- const unsigned long actual_processors = physical_processors();
- if (actual_processors >= server_processors) {
- result = JNI_TRUE;
- }
- }
- JLI_TraceLauncher("unix_" LIBARCHNAME "_ServerClassMachine: %s\n",
- (result == JNI_TRUE ? "JNI_TRUE" : "JNI_FALSE"));
- return result;
-}
diff --git a/jdk/src/solaris/bin/ergo_zero.c b/jdk/src/solaris/bin/ergo_zero.c
deleted file mode 100644
index 9261a423de6..00000000000
--- a/jdk/src/solaris/bin/ergo_zero.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 1998, 2007, 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 "ergo.h"
-
-
-/* Methods for solaris-sparc and linux-sparc: these are easy. */
-
-/* Ask the OS how many processors there are. */
-static unsigned long
-physical_processors(void) {
- const unsigned long sys_processors = sysconf(_SC_NPROCESSORS_CONF);
-
- JLI_TraceLauncher("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors);
- return sys_processors;
-}
-
-/* The sparc version of the "server-class" predicate. */
-jboolean
-ServerClassMachineImpl(void) {
- jboolean result = JNI_FALSE;
- /* How big is a server class machine? */
- const unsigned long server_processors = 2UL;
- const uint64_t server_memory = 2UL * GB;
- const uint64_t actual_memory = physical_memory();
-
- /* Is this a server class machine? */
- if (actual_memory >= server_memory) {
- const unsigned long actual_processors = physical_processors();
- if (actual_processors >= server_processors) {
- result = JNI_TRUE;
- }
- }
- JLI_TraceLauncher("unix_" LIBARCHNAME "_ServerClassMachine: %s\n",
- (result == JNI_TRUE ? "JNI_TRUE" : "JNI_FALSE"));
- return result;
-}
diff --git a/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
index 5ad8b8d54d8..be2426d7f72 100644
--- a/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
+++ b/jdk/src/solaris/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
@@ -68,6 +68,9 @@ import sun.net.www.protocol.http.HttpURLConnection;
public class NTLMAuthentication extends AuthenticationInfo {
private static final long serialVersionUID = 170L;
+ private static final NTLMAuthenticationCallback NTLMAuthCallback =
+ NTLMAuthenticationCallback.getNTLMAuthenticationCallback();
+
private String hostname;
private static String defaultDomain; /* Domain to use if not specified by user */
@@ -81,6 +84,14 @@ public class NTLMAuthentication extends AuthenticationInfo {
return false;
}
+ /**
+ * Returns true if the given site is trusted, i.e. we can try
+ * transparent Authentication.
+ */
+ public static boolean isTrustedSite(URL url) {
+ return NTLMAuthCallback.isTrustedSite(url);
+ }
+
private void init0() {
hostname = java.security.AccessController.doPrivileged(
diff --git a/jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java b/jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java
index 4499a08924c..af0dc1036bd 100644
--- a/jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java
+++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxDosFileAttributeView.java
@@ -27,6 +27,7 @@ package sun.nio.fs;
import java.nio.file.attribute.*;
import java.util.Map;
+import java.util.Set;
import java.io.IOException;
import sun.misc.Unsafe;
@@ -57,6 +58,10 @@ class LinuxDosFileAttributeView
private static final int DOS_XATTR_SYSTEM = 0x04;
private static final int DOS_XATTR_ARCHIVE = 0x20;
+ // the names of the DOS attributes (includes basic)
+ private static final Set dosAttributeNames =
+ Util.newSet(basicAttributeNames, READONLY_NAME, ARCHIVE_NAME, SYSTEM_NAME, HIDDEN_NAME);
+
LinuxDosFileAttributeView(UnixPath file, boolean followLinks) {
super(file, followLinks);
}
@@ -93,9 +98,10 @@ class LinuxDosFileAttributeView
public Map readAttributes(String[] attributes)
throws IOException
{
- AttributesBuilder builder = AttributesBuilder.create(attributes);
+ AttributesBuilder builder =
+ AttributesBuilder.create(dosAttributeNames, attributes);
DosFileAttributes attrs = readAttributes();
- addBasicAttributesToBuilder(attrs, builder);
+ addRequestedBasicAttributes(attrs, builder);
if (builder.match(READONLY_NAME))
builder.add(READONLY_NAME, attrs.isReadOnly());
if (builder.match(ARCHIVE_NAME))
diff --git a/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java
index b8b8c30f936..18309cb4450 100644
--- a/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java
+++ b/jdk/src/solaris/classes/sun/nio/fs/LinuxFileSystem.java
@@ -28,8 +28,6 @@ package sun.nio.fs;
import java.nio.file.*;
import java.io.IOException;
import java.util.*;
-import java.security.AccessController;
-import sun.security.action.GetPropertyAction;
import static sun.nio.fs.LinuxNativeDispatcher.*;
/**
@@ -37,42 +35,16 @@ import static sun.nio.fs.LinuxNativeDispatcher.*;
*/
class LinuxFileSystem extends UnixFileSystem {
- private final boolean hasInotify;
-
LinuxFileSystem(UnixFileSystemProvider provider, String dir) {
super(provider, dir);
-
- // assume X.Y[-Z] format
- String osversion = AccessController
- .doPrivileged(new GetPropertyAction("os.version"));
- String[] vers = Util.split(osversion, '.');
- assert vers.length >= 2;
-
- int majorVersion = Integer.parseInt(vers[0]);
- int minorVersion = Integer.parseInt(vers[1]);
- int microVersion = 0;
- if (vers.length > 2) {
- String[] microVers = Util.split(vers[2], '-');
- microVersion = (microVers.length > 0) ?
- Integer.parseInt(microVers[0]) : 0;
- }
-
- // inotify available since 2.6.13
- this.hasInotify = ((majorVersion > 2) ||
- (majorVersion == 2 && minorVersion > 6) ||
- ((majorVersion == 2) && (minorVersion == 6) && (microVersion >= 13)));
}
@Override
public WatchService newWatchService()
throws IOException
{
- if (hasInotify) {
- return new LinuxWatchService(this);
- } else {
- // use polling implementation on older kernels
- return new PollingWatchService();
- }
+ // assume 2.6.13 or newer
+ return new LinuxWatchService(this);
}
diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java
index c21a17707a8..ad0a2a00d12 100644
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixFileAttributeViews.java
@@ -123,6 +123,10 @@ class UnixFileAttributeViews {
private static final String OWNER_NAME = "owner";
private static final String GROUP_NAME = "group";
+ // the names of the posix attributes (incudes basic)
+ static final Set posixAttributeNames =
+ Util.newSet(basicAttributeNames, PERMISSIONS_NAME, OWNER_NAME, GROUP_NAME);
+
Posix(UnixPath file, boolean followLinks) {
super(file, followLinks);
}
@@ -172,9 +176,10 @@ class UnixFileAttributeViews {
* Invoked by readAttributes or sub-classes to add all matching posix
* attributes to the builder
*/
- final void addPosixAttributesToBuilder(PosixFileAttributes attrs,
+ final void addRequestedPosixAttributes(PosixFileAttributes attrs,
AttributesBuilder builder)
{
+ addRequestedBasicAttributes(attrs, builder);
if (builder.match(PERMISSIONS_NAME))
builder.add(PERMISSIONS_NAME, attrs.permissions());
if (builder.match(OWNER_NAME))
@@ -184,13 +189,13 @@ class UnixFileAttributeViews {
}
@Override
- public Map readAttributes(String[] attributes)
+ public Map readAttributes(String[] requested)
throws IOException
{
- AttributesBuilder builder = AttributesBuilder.create(attributes);
+ AttributesBuilder builder =
+ AttributesBuilder.create(posixAttributeNames, requested);
PosixFileAttributes attrs = readAttributes();
- addBasicAttributesToBuilder(attrs, builder);
- addPosixAttributesToBuilder(attrs, builder);
+ addRequestedPosixAttributes(attrs, builder);
return builder.unmodifiableMap();
}
@@ -287,6 +292,12 @@ class UnixFileAttributeViews {
private static final String GID_NAME = "gid";
private static final String CTIME_NAME = "ctime";
+ // the names of the unix attributes (including posix)
+ static final Set unixAttributeNames =
+ Util.newSet(posixAttributeNames,
+ MODE_NAME, INO_NAME, DEV_NAME, RDEV_NAME,
+ NLINK_NAME, UID_NAME, GID_NAME, CTIME_NAME);
+
Unix(UnixPath file, boolean followLinks) {
super(file, followLinks);
}
@@ -316,13 +327,13 @@ class UnixFileAttributeViews {
}
@Override
- public Map readAttributes(String[] attributes)
+ public Map readAttributes(String[] requested)
throws IOException
{
- AttributesBuilder builder = AttributesBuilder.create(attributes);
+ AttributesBuilder builder =
+ AttributesBuilder.create(unixAttributeNames, requested);
UnixFileAttributes attrs = readAttributes();
- addBasicAttributesToBuilder(attrs, builder);
- addPosixAttributesToBuilder(attrs, builder);
+ addRequestedPosixAttributes(attrs, builder);
if (builder.match(MODE_NAME))
builder.add(MODE_NAME, attrs.mode());
if (builder.match(INO_NAME))
diff --git a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java
index 9ec49b8d37a..b392b56b7e9 100644
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixPath.java
@@ -606,7 +606,9 @@ class UnixPath
@Override
public boolean startsWith(Path other) {
- UnixPath that = toUnixPath(other);
+ if (!(Objects.requireNonNull(other) instanceof UnixPath))
+ return false;
+ UnixPath that = (UnixPath)other;
// other path is longer
if (that.path.length > path.length)
@@ -655,7 +657,9 @@ class UnixPath
@Override
public boolean endsWith(Path other) {
- UnixPath that = toUnixPath(other);
+ if (!(Objects.requireNonNull(other) instanceof UnixPath))
+ return false;
+ UnixPath that = (UnixPath)other;
int thisLen = path.length;
int thatLen = that.path.length;
diff --git a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c
index e6eaa0aa2f5..9a5b78e7723 100644
--- a/jdk/src/solaris/native/java/net/Inet4AddressImpl.c
+++ b/jdk/src/solaris/native/java/net/Inet4AddressImpl.c
@@ -60,7 +60,7 @@ Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
char hostname[MAXHOSTNAMELEN+1];
hostname[0] = '\0';
- if (JVM_GetHostName(hostname, MAXHOSTNAMELEN)) {
+ if (JVM_GetHostName(hostname, sizeof(hostname))) {
/* Something went wrong, maybe networking is not setup? */
strcpy(hostname, "localhost");
} else {
@@ -83,6 +83,9 @@ Java_java_net_Inet4AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
char *buf2[HENT_BUF_SIZE/(sizeof (char *))];
int h_error=0;
+ // ensure null-terminated
+ hostname[MAXHOSTNAMELEN] = '\0';
+
#ifdef __GLIBC__
gethostbyname_r(hostname, &res, (char*)buf, sizeof(buf), &hp, &h_error);
#else
diff --git a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c
index 5db03bf36fa..835969d7761 100644
--- a/jdk/src/solaris/native/java/net/Inet6AddressImpl.c
+++ b/jdk/src/solaris/native/java/net/Inet6AddressImpl.c
@@ -64,10 +64,12 @@ Java_java_net_Inet6AddressImpl_getLocalHostName(JNIEnv *env, jobject this) {
char hostname[NI_MAXHOST+1];
hostname[0] = '\0';
- if (JVM_GetHostName(hostname, MAXHOSTNAMELEN)) {
+ if (JVM_GetHostName(hostname, sizeof(hostname))) {
/* Something went wrong, maybe networking is not setup? */
strcpy(hostname, "localhost");
} else {
+ // ensure null-terminated
+ hostname[NI_MAXHOST] = '\0';
#ifdef __linux__
/* On Linux gethostname() says "host.domain.sun.com". On
* Solaris gethostname() says "host", so extra work is needed.
diff --git a/jdk/src/solaris/native/sun/awt/awt_DrawingSurface.c b/jdk/src/solaris/native/sun/awt/awt_DrawingSurface.c
index 0c1275b3bc2..f84c08edf66 100644
--- a/jdk/src/solaris/native/sun/awt/awt_DrawingSurface.c
+++ b/jdk/src/solaris/native/sun/awt/awt_DrawingSurface.c
@@ -302,6 +302,7 @@ awt_DrawingSurface_FreeDrawingSurfaceInfo(JAWT_DrawingSurfaceInfo* dsi)
#ifdef DEBUG
fprintf(stderr, "Drawing Surface Info is NULL\n");
#endif
+ return;
}
free(dsi->platformInfo);
free(dsi);
diff --git a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c
index 45184950931..b548df4bf5d 100644
--- a/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c
+++ b/jdk/src/solaris/native/sun/awt/awt_GraphicsEnv.c
@@ -240,7 +240,7 @@ makeDefaultConfig(JNIEnv *env, int screen) {
AwtGraphicsConfigDataPtr defaultConfig;
int xinawareScreen = 0;
- VisualID forcedVisualID, defaultVisualID;
+ VisualID forcedVisualID = 0, defaultVisualID;
char *forcedVisualStr;
XVisualInfo vinfo;
long mask;
@@ -254,7 +254,7 @@ makeDefaultConfig(JNIEnv *env, int screen) {
if ((forcedVisualStr = getenv("FORCEDEFVIS"))) {
mask = VisualIDMask | VisualScreenMask;
- if (sscanf(forcedVisualStr, "%x", &forcedVisualID) > 0 &&
+ if (sscanf(forcedVisualStr, "%lx", &forcedVisualID) > 0 &&
forcedVisualID > 0)
{
vinfo.visualid = forcedVisualID;
diff --git a/jdk/src/solaris/native/sun/nio/ch/Net.c b/jdk/src/solaris/native/sun/nio/ch/Net.c
index c43664c5000..9f9b4669a8e 100644
--- a/jdk/src/solaris/native/sun/nio/ch/Net.c
+++ b/jdk/src/solaris/native/sun/nio/ch/Net.c
@@ -154,6 +154,22 @@ Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
return (ipv6_available()) ? JNI_TRUE : JNI_FALSE;
}
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
+{
+ return JNI_TRUE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
+{
+#ifdef __solaris__
+ return JNI_TRUE;
+#else
+ return JNI_FALSE;
+#endif
+}
+
JNIEXPORT int JNICALL
Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
jboolean stream, jboolean reuse)
diff --git a/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java b/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java
index 65969a877d5..5590523b6ae 100644
--- a/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java
+++ b/jdk/src/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java
@@ -26,6 +26,7 @@ package java.net;
import java.io.IOException;
import java.io.FileDescriptor;
+import sun.net.ResourceManager;
/**
* This class defines the plain DatagramSocketImpl that is used for all
@@ -108,6 +109,7 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
protected void close() {
if (fd != null || fd1 != null) {
datagramSocketClose();
+ ResourceManager.afterUdpClose();
fd = null;
fd1 = null;
}
diff --git a/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java b/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
index c9c26517d9b..c4b20db6495 100644
--- a/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
+++ b/jdk/src/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java
@@ -45,6 +45,9 @@ public class NTLMAuthentication extends AuthenticationInfo {
private static final long serialVersionUID = 100L;
+ private static final NTLMAuthenticationCallback NTLMAuthCallback =
+ NTLMAuthenticationCallback.getNTLMAuthenticationCallback();
+
private String hostname;
private static String defaultDomain; /* Domain to use if not specified by user */
@@ -142,6 +145,14 @@ public class NTLMAuthentication extends AuthenticationInfo {
return true;
}
+ /**
+ * Returns true if the given site is trusted, i.e. we can try
+ * transparent Authentication.
+ */
+ public static boolean isTrustedSite(URL url) {
+ return NTLMAuthCallback.isTrustedSite(url);
+ }
+
/**
* Not supported. Must use the setHeaders() method
*/
diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java
index 8a81b87a0ab..67e5be670e0 100644
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsFileAttributeViews.java
@@ -157,6 +157,11 @@ class WindowsFileAttributeViews {
private static final String HIDDEN_NAME = "hidden";
private static final String ATTRIBUTES_NAME = "attributes";
+ // the names of the DOS attribtues (includes basic)
+ static final Set dosAttributeNames =
+ Util.newSet(basicAttributeNames,
+ READONLY_NAME, ARCHIVE_NAME, SYSTEM_NAME, HIDDEN_NAME, ATTRIBUTES_NAME);
+
Dos(WindowsPath file, boolean followLinks) {
super(file, followLinks);
}
@@ -193,9 +198,10 @@ class WindowsFileAttributeViews {
public Map readAttributes(String[] attributes)
throws IOException
{
- AttributesBuilder builder = AttributesBuilder.create(attributes);
+ AttributesBuilder builder =
+ AttributesBuilder.create(dosAttributeNames, attributes);
WindowsFileAttributes attrs = readAttributes();
- addBasicAttributesToBuilder(attrs, builder);
+ addRequestedBasicAttributes(attrs, builder);
if (builder.match(READONLY_NAME))
builder.add(READONLY_NAME, attrs.isReadOnly());
if (builder.match(ARCHIVE_NAME))
diff --git a/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java b/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java
index 26c2b26ce8e..eb35de8167e 100644
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsPath.java
@@ -646,7 +646,9 @@ class WindowsPath extends AbstractPath {
@Override
public boolean startsWith(Path obj) {
- WindowsPath other = toWindowsPath(obj);
+ if (!(Objects.requireNonNull(obj) instanceof WindowsPath))
+ return false;
+ WindowsPath other = (WindowsPath)obj;
// if this path has a root component the given path's root must match
if (!this.root.equalsIgnoreCase(other.root)) {
@@ -675,7 +677,9 @@ class WindowsPath extends AbstractPath {
@Override
public boolean endsWith(Path obj) {
- WindowsPath other = toWindowsPath(obj);
+ if (!(Objects.requireNonNull(obj) instanceof WindowsPath))
+ return false;
+ WindowsPath other = (WindowsPath)obj;
// other path is longer
if (other.path.length() > this.path.length()) {
diff --git a/jdk/src/windows/native/sun/nio/ch/Net.c b/jdk/src/windows/native/sun/nio/ch/Net.c
index b415cdfc3e2..75c9ba4ce66 100644
--- a/jdk/src/windows/native/sun/nio/ch/Net.c
+++ b/jdk/src/windows/native/sun/nio/ch/Net.c
@@ -100,6 +100,18 @@ Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl)
return JNI_FALSE;
}
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
+{
+ return JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
+{
+ return JNI_FALSE;
+}
+
JNIEXPORT jint JNICALL
Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
jboolean stream, jboolean reuse)
diff --git a/jdk/src/windows/native/sun/security/krb5/NativeCreds.c b/jdk/src/windows/native/sun/security/krb5/NativeCreds.c
index 7533cc12811..91ed2cb84bb 100644
--- a/jdk/src/windows/native/sun/security/krb5/NativeCreds.c
+++ b/jdk/src/windows/native/sun/security/krb5/NativeCreds.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -1032,12 +1032,12 @@ jobject BuildKerberosTime(JNIEnv *env, PLARGE_INTEGER kerbtime) {
// XXX Cannot use %02.2ld, because the leading 0 is ignored for integers.
// So, print them to strings, and then print them to the master string with a
// format pattern that makes it two digits and prefix with a 0 if necessary.
- swprintf( (wchar_t *)month, L"%2.2d", systemTime.wMonth);
- swprintf( (wchar_t *)day, L"%2.2d", systemTime.wDay);
- swprintf( (wchar_t *)hour, L"%2.2d", systemTime.wHour);
- swprintf( (wchar_t *)minute, L"%2.2d", systemTime.wMinute);
- swprintf( (wchar_t *)second, L"%2.2d", systemTime.wSecond);
- swprintf( (wchar_t *)timeString,
+ swprintf( (wchar_t *)month, 3, L"%2.2d", systemTime.wMonth);
+ swprintf( (wchar_t *)day, 3, L"%2.2d", systemTime.wDay);
+ swprintf( (wchar_t *)hour, 3, L"%2.2d", systemTime.wHour);
+ swprintf( (wchar_t *)minute, 3, L"%2.2d", systemTime.wMinute);
+ swprintf( (wchar_t *)second, 3, L"%2.2d", systemTime.wSecond);
+ swprintf( (wchar_t *)timeString, 16,
L"%ld%02.2s%02.2s%02.2s%02.2s%02.2sZ",
systemTime.wYear,
month,
diff --git a/jdk/src/windows/native/sun/tools/attach/WindowsVirtualMachine.c b/jdk/src/windows/native/sun/tools/attach/WindowsVirtualMachine.c
index 07b136aba2d..6086ddf30f0 100644
--- a/jdk/src/windows/native/sun/tools/attach/WindowsVirtualMachine.c
+++ b/jdk/src/windows/native/sun/tools/attach/WindowsVirtualMachine.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2011, 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
@@ -173,24 +173,45 @@ JNIEXPORT jbyteArray JNICALL Java_sun_tools_attach_WindowsVirtualMachine_generat
JNIEXPORT jlong JNICALL Java_sun_tools_attach_WindowsVirtualMachine_openProcess
(JNIEnv *env, jclass cls, jint pid)
{
- HANDLE hProcess;
+ HANDLE hProcess = NULL;
- /*
- * Attempt to open process. If it fails then we try to enable the
- * SE_DEBUG_NAME privilege and retry.
- */
- hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
- if (hProcess == NULL && GetLastError() == ERROR_ACCESS_DENIED) {
- hProcess = doPrivilegedOpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
+ if (pid == (jint) GetCurrentProcessId()) {
+ /* process is attaching to itself; get a pseudo handle instead */
+ hProcess = GetCurrentProcess();
+ /* duplicate the pseudo handle so it can be used in more contexts */
+ if (DuplicateHandle(hProcess, hProcess, hProcess, &hProcess,
+ PROCESS_ALL_ACCESS, FALSE, 0) == 0) {
+ /*
+ * Could not duplicate the handle which isn't a good sign,
+ * but we'll try again with OpenProcess() below.
+ */
+ hProcess = NULL;
+ }
}
if (hProcess == NULL) {
- if (GetLastError() == ERROR_INVALID_PARAMETER) {
- JNU_ThrowIOException(env, "no such process");
- } else {
- JNU_ThrowIOExceptionWithLastError(env, "OpenProcess failed");
+ /*
+ * Attempt to open process. If it fails then we try to enable the
+ * SE_DEBUG_NAME privilege and retry.
+ */
+ hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
+ if (hProcess == NULL && GetLastError() == ERROR_ACCESS_DENIED) {
+ hProcess = doPrivilegedOpenProcess(PROCESS_ALL_ACCESS, FALSE,
+ (DWORD)pid);
+ }
+
+ if (hProcess == NULL) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ JNU_ThrowIOException(env, "no such process");
+ } else {
+ char err_mesg[255];
+ /* include the last error in the default detail message */
+ sprintf(err_mesg, "OpenProcess(pid=%d) failed; LastError=0x%x",
+ (int)pid, (int)GetLastError());
+ JNU_ThrowIOExceptionWithLastError(env, err_mesg);
+ }
+ return (jlong)0;
}
- return (jlong)0;
}
/*
diff --git a/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp b/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp
index df0f263ddfc..1deff60252a 100644
--- a/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp
+++ b/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp
@@ -3699,7 +3699,9 @@ static void matchPaperSize(HDC printDC, HGLOBAL hDevMode, HGLOBAL hDevNames,
double* newWid, double *newHgt,
WORD* paperSize) {
- const double epsilon = 0.50;
+ // Tolerated differences in comparing page dimensions between passed in
+ // "orig" media with that of Windows' device.
+ const double epsilon = 3.6; // (1/72) of an inch
const double tolerance = (1.0 * 72.0); // # inches * 72
*newWid = origWid;
diff --git a/jdk/test/Makefile b/jdk/test/Makefile
index d26d19c544a..d1171b96027 100644
--- a/jdk/test/Makefile
+++ b/jdk/test/Makefile
@@ -399,12 +399,12 @@ $(foreach i,$1,$(wildcard ${i})) $(foreach i,$1,$(wildcard closed/${i}))
endef
# Running batches of tests with or without samevm
define RunSamevmBatch
-$(ECHO) "Running tests in samevm mode: $(call TestDirs, $?)"
-$(MAKE) TESTDIRS="$(call TestDirs, $?)" USE_JTREG_SAMEVM=true UNIQUE_DIR=$@ jtreg_tests
+$(ECHO) "Running tests in samevm mode: $?"
+$(MAKE) TESTDIRS="$?" USE_JTREG_SAMEVM=true UNIQUE_DIR=$@ jtreg_tests
endef
define RunOthervmBatch
-$(ECHO) "Running tests in othervm mode: $(call TestDirs, $?)"
-$(MAKE) TESTDIRS="$(call TestDirs, $?)" USE_JTREG_SAMEVM=false UNIQUE_DIR=$@ jtreg_tests
+$(ECHO) "Running tests in othervm mode: $?"
+$(MAKE) TESTDIRS="$?" USE_JTREG_SAMEVM=false UNIQUE_DIR=$@ jtreg_tests
endef
define SummaryInfo
$(ECHO) "########################################################"
@@ -420,27 +420,29 @@ JDK_ALL_TARGETS =
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has problems, and doesn't help performance as much as others.
JDK_ALL_TARGETS += jdk_awt
-jdk_awt: com/sun/awt java/awt sun/awt
+jdk_awt: $(call TestDirs, com/sun/awt java/awt sun/awt)
$(call RunOthervmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_beans1
-jdk_beans1: java/beans/beancontext java/beans/PropertyChangeSupport \
+jdk_beans1: $(call TestDirs, \
+ java/beans/beancontext java/beans/PropertyChangeSupport \
java/beans/Introspector java/beans/Performance \
- java/beans/VetoableChangeSupport java/beans/Statement
+ java/beans/VetoableChangeSupport java/beans/Statement)
$(call RunSamevmBatch)
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_beans2
-jdk_beans2: java/beans/Beans java/beans/EventHandler java/beans/XMLDecoder \
- java/beans/PropertyEditor
+jdk_beans2: $(call TestDirs, \
+ java/beans/Beans java/beans/EventHandler java/beans/XMLDecoder \
+ java/beans/PropertyEditor)
$(call RunOthervmBatch)
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_beans3
-jdk_beans3: java/beans/XMLEncoder
+jdk_beans3: $(call TestDirs, java/beans/XMLEncoder)
$(call RunOthervmBatch)
# All beans tests
@@ -449,24 +451,24 @@ jdk_beans: jdk_beans1 jdk_beans2 jdk_beans3
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_io
-jdk_io: java/io
+jdk_io: $(call TestDirs, java/io)
$(call RunSamevmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_lang
-jdk_lang: java/lang
+jdk_lang: $(call TestDirs, java/lang)
$(call RunSamevmBatch)
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_management1
-jdk_management1: javax/management
+jdk_management1: $(call TestDirs, javax/management)
$(call RunOthervmBatch)
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_management2
-jdk_management2: com/sun/jmx com/sun/management sun/management
+jdk_management2: $(call TestDirs, com/sun/jmx com/sun/management sun/management)
$(call RunOthervmBatch)
# All management tests
@@ -475,36 +477,37 @@ jdk_management: jdk_management1 jdk_management2
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_math
-jdk_math: java/math
+jdk_math: $(call TestDirs, java/math)
$(call RunSamevmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_misc
-jdk_misc: demo javax/imageio javax/naming javax/print javax/script \
+jdk_misc: $(call TestDirs, \
+ demo javax/imageio javax/naming javax/print javax/script \
javax/smartcardio javax/sound com/sun/java com/sun/jndi \
- com/sun/org sun/misc sun/pisces
+ com/sun/org com/sun/xml sun/misc sun/pisces)
$(call RunSamevmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_net
-jdk_net: com/sun/net java/net sun/net
+jdk_net: $(call TestDirs, com/sun/net java/net sun/net)
$(call RunSamevmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_nio1
-jdk_nio1: java/nio/file
+jdk_nio1: $(call TestDirs, java/nio/file)
$(call RunSamevmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_nio2
-jdk_nio2: java/nio/Buffer java/nio/ByteOrder \
- java/nio/channels java/nio/BufferPoolMXBean java/nio/MappedByteBuffer
+jdk_nio2: $(call TestDirs, java/nio/Buffer java/nio/ByteOrder \
+ java/nio/channels java/nio/BufferPoolMXBean java/nio/MappedByteBuffer)
$(call SharedLibraryPermissions,java/nio/channels)
$(call RunSamevmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_nio3
-jdk_nio3: com/sun/nio sun/nio
+jdk_nio3: $(call TestDirs, com/sun/nio sun/nio)
$(call RunSamevmBatch)
# All nio tests
@@ -514,24 +517,25 @@ jdk_nio: jdk_nio1 jdk_nio2 jdk_nio3
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_rmi
-jdk_rmi: java/rmi javax/rmi sun/rmi
+jdk_rmi: $(call TestDirs, java/rmi javax/rmi sun/rmi)
$(call RunOthervmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_security1
-jdk_security1: java/security
+jdk_security1: $(call TestDirs, java/security)
$(call RunSamevmBatch)
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_security2
-jdk_security2: javax/crypto com/sun/crypto
+jdk_security2: $(call TestDirs, javax/crypto com/sun/crypto)
$(call RunOthervmBatch)
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_security3
-jdk_security3: com/sun/security lib/security javax/security sun/security
+jdk_security3: $(call TestDirs, com/sun/security lib/security \
+ javax/security sun/security)
$(call SharedLibraryPermissions,sun/security)
$(call RunOthervmBatch)
@@ -542,23 +546,25 @@ jdk_security: jdk_security1 jdk_security2 jdk_security3
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has problems, and doesn't help performance as much as others.
JDK_ALL_TARGETS += jdk_swing
-jdk_swing: javax/swing sun/java2d
+jdk_swing: $(call TestDirs, javax/swing sun/java2d)
$(call RunOthervmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_text
-jdk_text: java/text sun/text
+jdk_text: $(call TestDirs, java/text sun/text)
$(call RunSamevmBatch)
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_tools1
-jdk_tools1: com/sun/jdi
+jdk_tools1: $(call TestDirs, com/sun/jdi)
$(call RunSamevmBatch)
# Stable othervm testruns (minus items from PROBLEM_LIST)
# Using samevm has serious problems with these tests
JDK_ALL_TARGETS += jdk_tools2
-jdk_tools2: com/sun/tools sun/jvmstat sun/tools tools vm com/sun/servicetag com/sun/tracing
+jdk_tools2: $(call TestDirs, \
+ com/sun/tools sun/jvmstat sun/tools tools vm \
+ com/sun/servicetag com/sun/tracing)
$(call SharedLibraryPermissions,tools/launcher)
$(call RunSamevmBatch)
@@ -568,7 +574,7 @@ jdk_tools: jdk_tools1 jdk_tools2
# Stable samevm testruns (minus items from PROBLEM_LIST)
JDK_ALL_TARGETS += jdk_util
-jdk_util: java/util sun/util
+jdk_util: $(call TestDirs, java/util sun/util)
$(call RunSamevmBatch)
# ------------------------------------------------------------------
diff --git a/jdk/test/java/awt/font/TextLayout/CombiningPerf.java b/jdk/test/java/awt/font/TextLayout/CombiningPerf.java
new file mode 100644
index 00000000000..d51e586e507
--- /dev/null
+++ b/jdk/test/java/awt/font/TextLayout/CombiningPerf.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2011, 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 6328154 6962082
+ * @summary ensure that ascii, and latin-1 text without combining marks, both layout faster
+ * than latin-1 text with combining marks. The presumption is then that the canonical
+ * GSUB table is being run only on the latter and not on either of the former.
+ */
+
+import java.awt.Font;
+import java.awt.GraphicsEnvironment;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+
+import static java.awt.Font.*;
+
+public class CombiningPerf {
+ private static Font font;
+ private static FontRenderContext frc;
+
+ public static void main(String[] args) throws Exception {
+ System.err.println("start");
+
+ GraphicsEnvironment.getLocalGraphicsEnvironment();
+
+ font = new Font("Lucida Sans Regular", PLAIN, 12);
+ frc = new FontRenderContext(null, false, false);
+
+ String ascii = "the characters are critical noodles?";
+ String french = "l'aper\u00e7u caract\u00e8re one \u00e9t\u00e9 cr\u00e9\u00e9s";
+ String frenchX = "l'aper\u00e7u caracte\u0300re one e\u0301te\u0301 ere\u0301e\u0301s";
+
+ // warmup
+ for (int i = 0; i < 100; ++i) {
+ TextLayout tl = new TextLayout(french, font, frc);
+ tl = new TextLayout(ascii, font, frc);
+ tl = new TextLayout(frenchX, font, frc);
+ }
+ /**/
+ long atime = test(ascii);
+ System.err.println("atime: " + (atime/1000000.0) + " length: " + ascii.length());
+
+ long ftime = test(french);
+ System.err.println("ftime: " + (ftime/1000000.0) + " length: " + french.length());
+
+ long xtime = test(frenchX);
+ System.err.println("xtime: " + (xtime/1000000.0) + " length: " + frenchX.length());
+
+ long limit = xtime * 2 / 3;
+ if (atime > limit || ftime > limit) {
+ throw new Exception("took too long");
+ }
+ /**/
+ }
+
+ private static long test(String text) {
+ long start = System.nanoTime();
+ for (int i = 0; i < 2000; ++i) {
+ TextLayout tl = new TextLayout(text, font, frc);
+ }
+ return System.nanoTime() - start;
+ }
+}
diff --git a/jdk/test/java/awt/font/TextLayout/KernCrash.java b/jdk/test/java/awt/font/TextLayout/KernCrash.java
new file mode 100644
index 00000000000..50e44d4c30d
--- /dev/null
+++ b/jdk/test/java/awt/font/TextLayout/KernCrash.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2011, 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.*;
+import java.awt.*;
+import java.awt.font.*;
+import java.util.*;
+
+/**
+ * Shows (top) with kerning, (middle) without, (bottom) also without.
+ *
+ * @bug 7017324
+ */
+public class KernCrash extends Frame {
+ private static Font font0;
+ private static Font font1;
+ private static Font font2;
+
+ public static void main(String[] args) throws Exception {
+ HashMap attrs = new HashMap();
+ font0 = Font.createFont(Font.TRUETYPE_FONT, new File("Vera.ttf"));
+ System.out.println("using " + font0);
+ attrs.put(TextAttribute.SIZE, new Float(58f));
+ font1 = font0.deriveFont(attrs);
+ attrs.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
+ font2 = font0.deriveFont(attrs);
+
+ KernCrash f = new KernCrash();
+ f.setTitle("Kerning Crash");
+ f.setSize(600, 300);
+ f.setForeground(Color.black);
+ f.show();
+ }
+
+ public void paint(Graphics g) {
+ Graphics2D g2 = (Graphics2D)g;
+ FontRenderContext frc = g2.getFontRenderContext();
+ TextLayout layout = new TextLayout("text", font2, frc);
+ layout.draw(g2, 10, 150);
+
+ String s = "WAVATastic";
+ TextLayout layout2 = new TextLayout(s, font1, frc);
+ layout2.draw(g2, 10, 200);
+ TextLayout layout3 = new TextLayout(s, font2, frc);
+ layout3.draw(g2, 10, 100);
+ }
+}
diff --git a/hotspot/test/compiler/6987555/Test6987555.java b/jdk/test/java/lang/invoke/6987555/Test6987555.java
similarity index 99%
rename from hotspot/test/compiler/6987555/Test6987555.java
rename to jdk/test/java/lang/invoke/6987555/Test6987555.java
index a438fee8dd1..465da236d7c 100644
--- a/hotspot/test/compiler/6987555/Test6987555.java
+++ b/jdk/test/java/lang/invoke/6987555/Test6987555.java
@@ -30,7 +30,7 @@
* @run main/othervm -Xint -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6987555
*/
-import java.dyn.*;
+import java.lang.invoke.*;
public class Test6987555 {
private static final Class CLASS = Test6987555.class;
diff --git a/hotspot/test/compiler/6991596/Test6991596.java b/jdk/test/java/lang/invoke/6991596/Test6991596.java
similarity index 98%
rename from hotspot/test/compiler/6991596/Test6991596.java
rename to jdk/test/java/lang/invoke/6991596/Test6991596.java
index aff08c88641..e02bcfc819e 100644
--- a/hotspot/test/compiler/6991596/Test6991596.java
+++ b/jdk/test/java/lang/invoke/6991596/Test6991596.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2011, 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
@@ -30,7 +30,7 @@
* @run main/othervm -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6991596
*/
-import java.dyn.*;
+import java.lang.invoke.*;
public class Test6991596 {
private static final Class CLASS = Test6991596.class;
@@ -47,7 +47,7 @@ public class Test6991596 {
}
// Helpers to get various methods.
- static MethodHandle getmh1(Class ret, Class arg) throws NoAccessException {
+ static MethodHandle getmh1(Class ret, Class arg) throws ReflectiveOperationException {
return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg));
}
static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) {
diff --git a/jdk/test/java/dyn/ClassValueTest.java b/jdk/test/java/lang/invoke/ClassValueTest.java
similarity index 94%
rename from jdk/test/java/dyn/ClassValueTest.java
rename to jdk/test/java/lang/invoke/ClassValueTest.java
index f917e9581da..59c5a658c7e 100644
--- a/jdk/test/java/dyn/ClassValueTest.java
+++ b/jdk/test/java/lang/invoke/ClassValueTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -26,21 +26,21 @@
/* @test
* @summary tests for class-specific values
* @compile ClassValueTest.java
- * @run junit/othervm test.java.dyn.ClassValueTest
+ * @run junit/othervm test.java.lang.invoke.ClassValueTest
*/
/*
Manually:
- $ $JAVA7X_HOME/bin/javac -d foo -cp $JUNIT4_JAR test/java/dyn/ClassValueTest.java
- $ $JAVA7X_HOME/bin/java -cp foo:$JUNIT4_JAR org.junit.runner.JUnitCore test.java.dyn.ClassValueTest
+ $ $JAVA7X_HOME/bin/javac -d foo -cp $JUNIT4_JAR test/java/lang/invoke/ClassValueTest.java
+ $ $JAVA7X_HOME/bin/java -cp foo:$JUNIT4_JAR org.junit.runner.JUnitCore test.java.lang.invoke.ClassValueTest
Output: .testAdd => 1000 : Integer
*/
-package test.java.dyn;
+package test.java.lang.invoke;
import java.util.*;
-import java.dyn.*;
+import java.lang.invoke.*;
import org.junit.*;
import static org.junit.Assert.*;
diff --git a/jdk/test/java/dyn/InvokeDynamicPrintArgs.java b/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java
similarity index 89%
rename from jdk/test/java/dyn/InvokeDynamicPrintArgs.java
rename to jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java
index 233c4fc316c..7089e959223 100644
--- a/jdk/test/java/dyn/InvokeDynamicPrintArgs.java
+++ b/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2011, 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
@@ -29,19 +29,19 @@
* indify.Indify
* --verify-specifier-count=3 --transitionalJSR292=false
* --expand-properties --classpath ${test.classes}
- * --java test.java.dyn.InvokeDynamicPrintArgs --check-output
+ * --java test.java.lang.invoke.InvokeDynamicPrintArgs --check-output
*/
-package test.java.dyn;
+package test.java.lang.invoke;
import org.junit.Test;
import java.util.*;
import java.io.*;
-import java.dyn.*;
-import static java.dyn.MethodHandles.*;
-import static java.dyn.MethodType.*;
+import java.lang.invoke.*;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
public class InvokeDynamicPrintArgs {
public static void main(String... av) throws Throwable {
@@ -65,7 +65,7 @@ public class InvokeDynamicPrintArgs {
String[] args = new String[]{
"--verify-specifier-count=3", "--transitionalJSR292=false",
"--expand-properties", "--classpath", testClassPath,
- "--java", "test.java.dyn.InvokeDynamicPrintArgs", "--check-output"
+ "--java", "test.java.lang.invoke.InvokeDynamicPrintArgs", "--check-output"
};
System.err.println("Indify: "+Arrays.toString(args));
indify.Indify.main(args);
@@ -97,11 +97,11 @@ public class InvokeDynamicPrintArgs {
}
private static final String[] EXPECT_OUTPUT = {
"Printing some argument lists, starting with a empty one:",
- "[test.java.dyn.InvokeDynamicPrintArgs, nothing, ()void][]",
- "[test.java.dyn.InvokeDynamicPrintArgs, bar, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar arg, 1]",
- "[test.java.dyn.InvokeDynamicPrintArgs, bar2, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar2 arg, 222]",
- "[test.java.dyn.InvokeDynamicPrintArgs, baz, (String,int,double)void, 1234.5][baz arg, 2, 3.14]",
- "[test.java.dyn.InvokeDynamicPrintArgs, foo, (String)void][foo arg]",
+ "[test.java.lang.invoke.InvokeDynamicPrintArgs, nothing, ()void][]",
+ "[test.java.lang.invoke.InvokeDynamicPrintArgs, bar, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar arg, 1]",
+ "[test.java.lang.invoke.InvokeDynamicPrintArgs, bar2, (String,int)void, class java.lang.Void, void type!, 1, 234.5, 67.5, 89][bar2 arg, 222]",
+ "[test.java.lang.invoke.InvokeDynamicPrintArgs, baz, (String,int,double)void, 1234.5][baz arg, 2, 3.14]",
+ "[test.java.lang.invoke.InvokeDynamicPrintArgs, foo, (String)void][foo arg]",
"Done printing argument lists."
};
diff --git a/jdk/test/java/dyn/InvokeGenericTest.java b/jdk/test/java/lang/invoke/InvokeGenericTest.java
similarity index 97%
rename from jdk/test/java/dyn/InvokeGenericTest.java
rename to jdk/test/java/lang/invoke/InvokeGenericTest.java
index bae888060a0..f1aaf9eaa71 100644
--- a/jdk/test/java/dyn/InvokeGenericTest.java
+++ b/jdk/test/java/lang/invoke/InvokeGenericTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2011, 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
@@ -24,16 +24,16 @@
*/
/* @test
- * @summary unit tests for java.dyn.MethodHandle.invokeGeneric
+ * @summary unit tests for java.lang.invoke.MethodHandle.invokeGeneric
* @compile -XDallowTransitionalJSR292=no -target 7 InvokeGenericTest.java
- * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.InvokeGenericTest
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.lang.invoke.InvokeGenericTest
*/
-package test.java.dyn;
+package test.java.lang.invoke;
-import java.dyn.*;
-import static java.dyn.MethodHandles.*;
-import static java.dyn.MethodType.*;
+import java.lang.invoke.*;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
import java.lang.reflect.*;
import java.util.*;
import org.junit.*;
@@ -49,7 +49,7 @@ public class InvokeGenericTest {
// How much output?
static int verbosity = 0;
static {
- String vstr = System.getProperty("test.java.dyn.InvokeGenericTest.verbosity");
+ String vstr = System.getProperty("test.java.lang.invoke.InvokeGenericTest.verbosity");
if (vstr != null) verbosity = Integer.parseInt(vstr);
}
@@ -216,7 +216,7 @@ public class InvokeGenericTest {
if (wrap != null) {
return wrap;
}
-// import sun.dyn.util.Wrapper;
+// import sun.invoke.util.Wrapper;
// Wrapper wrap = Wrapper.forBasicType(dst);
// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
// wrap = Wrapper.forWrapperType(dst);
diff --git a/jdk/test/java/dyn/JavaDocExamplesTest.java b/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
similarity index 88%
rename from jdk/test/java/dyn/JavaDocExamplesTest.java
rename to jdk/test/java/lang/invoke/JavaDocExamplesTest.java
index 72a62851f82..7093ea2005a 100644
--- a/jdk/test/java/dyn/JavaDocExamplesTest.java
+++ b/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
@@ -24,27 +24,27 @@
*/
/* @test
- * @summary example code used in javadoc for java.dyn API
+ * @summary example code used in javadoc for java.lang.invoke API
* @compile -XDallowTransitionalJSR292=no JavaDocExamplesTest.java
- * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.JavaDocExamplesTest
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.lang.invoke.JavaDocExamplesTest
*/
/*
---- To run outside jtreg:
$ $JAVA7X_HOME/bin/javac -cp $JUNIT4_JAR -d /tmp/Classes \
- $DAVINCI/sources/jdk/test/java/dyn/JavaDocExamplesTest.java
+ $DAVINCI/sources/jdk/test/java/lang/invoke/JavaDocExamplesTest.java
$ $JAVA7X_HOME/bin/java -cp $JUNIT4_JAR:/tmp/Classes \
-XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles \
- -Dtest.java.dyn.JavaDocExamplesTest.verbosity=1 \
- test.java.dyn.JavaDocExamplesTest
+ -Dtest.java.lang.invoke.JavaDocExamplesTest.verbosity=1 \
+ test.java.lang.invoke.JavaDocExamplesTest
----
*/
-package test.java.dyn;
+package test.java.lang.invoke;
-import java.dyn.*;
-import static java.dyn.MethodHandles.*;
-import static java.dyn.MethodType.*;
+import java.lang.invoke.*;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
import java.lang.reflect.*;
import java.util.*;
@@ -65,7 +65,7 @@ public class JavaDocExamplesTest {
org.junit.runner.JUnitCore.runClasses(JavaDocExamplesTest.class);
}
// How much output?
- static int verbosity = Integer.getInteger("test.java.dyn.JavaDocExamplesTest.verbosity", 0);
+ static int verbosity = Integer.getInteger("test.java.lang.invoke.JavaDocExamplesTest.verbosity", 0);
{}
static final private Lookup LOOKUP = lookup();
@@ -108,6 +108,16 @@ assertEquals("xy".hashCode(), (int) HASHCODE_3.invokeExact((Object)"xy"));
MethodHandle cat = lookup().findVirtual(String.class,
"concat", methodType(String.class, String.class));
assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
+MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
+assertEquals(bigType, d0.type());
+assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
+ }}
+ {{
+{} /// JAVADOC
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
MethodHandle d0 = dropArguments(cat, 0, String.class);
assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
MethodHandle d1 = dropArguments(cat, 1, String.class);
diff --git a/jdk/test/java/dyn/MethodHandlesTest.java b/jdk/test/java/lang/invoke/MethodHandlesTest.java
similarity index 99%
rename from jdk/test/java/dyn/MethodHandlesTest.java
rename to jdk/test/java/lang/invoke/MethodHandlesTest.java
index b44f262fa02..bae38f766bc 100644
--- a/jdk/test/java/dyn/MethodHandlesTest.java
+++ b/jdk/test/java/lang/invoke/MethodHandlesTest.java
@@ -24,15 +24,15 @@
*/
/* @test
- * @summary unit tests for java.dyn.MethodHandles
+ * @summary unit tests for java.lang.invoke.MethodHandles
* @compile -source 7 -target 7 -XDallowTransitionalJSR292=no MethodHandlesTest.java
- * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.MethodHandlesTest
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.lang.invoke.MethodHandlesTest
*/
-package test.java.dyn;
+package test.java.lang.invoke;
-import java.dyn.*;
-import java.dyn.MethodHandles.Lookup;
+import java.lang.invoke.*;
+import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.*;
import java.util.*;
import org.junit.*;
@@ -48,7 +48,7 @@ public class MethodHandlesTest {
// How much output?
static int verbosity = 0;
static {
- String vstr = System.getProperty("test.java.dyn.MethodHandlesTest.verbosity");
+ String vstr = System.getProperty("test.java.lang.invoke.MethodHandlesTest.verbosity");
if (vstr != null) verbosity = Integer.parseInt(vstr);
}
@@ -258,7 +258,7 @@ public class MethodHandlesTest {
if (wrap != null) {
return wrap;
}
-// import sun.dyn.util.Wrapper;
+// import sun.invoke.util.Wrapper;
// Wrapper wrap = Wrapper.forBasicType(dst);
// if (wrap == Wrapper.OBJECT && Wrapper.isWrapperType(dst))
// wrap = Wrapper.forWrapperType(dst);
@@ -2264,7 +2264,7 @@ public class MethodHandlesTest {
}
}
}
-// Local abbreviated copy of sun.dyn.util.ValueConversions
+// Local abbreviated copy of sun.invoke.util.ValueConversions
class ValueConversions {
private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
private static final Object[] NO_ARGS_ARRAY = {};
diff --git a/jdk/test/java/dyn/MethodTypeTest.java b/jdk/test/java/lang/invoke/MethodTypeTest.java
similarity index 82%
rename from jdk/test/java/dyn/MethodTypeTest.java
rename to jdk/test/java/lang/invoke/MethodTypeTest.java
index caadaa04a33..5cc32771624 100644
--- a/jdk/test/java/dyn/MethodTypeTest.java
+++ b/jdk/test/java/lang/invoke/MethodTypeTest.java
@@ -24,15 +24,14 @@
*/
/* @test
- * @summary unit tests for java.dyn.MethodType
+ * @summary unit tests for java.lang.invoke.MethodType
* @compile MethodTypeTest.java
- * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.dyn.MethodTypeTest
+ * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles test.java.lang.invoke.MethodTypeTest
*/
-package test.java.dyn;
+package test.java.lang.invoke;
-import sun.dyn.MemberName;
-import java.dyn.MethodType;
+import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.*;
@@ -163,18 +162,6 @@ public class MethodTypeTest {
assertSame(expResult, result);
}
- /**
- * Test of make method, of class MethodType.
- */
- @Test
- public void testMake_Method() {
- System.out.println("make (via MemberName.getMethodType)");
- MethodType expResult = MethodType.methodType(int.class, String.class);
- MemberName name = new MemberName(compareTo);
- MethodType result = name.getMethodType();
- assertSame(expResult, result);
- }
-
/**
* Test of make method, of class MethodType.
*/
@@ -476,10 +463,13 @@ public class MethodTypeTest {
@Test
public void testPortableSerialFormat() throws Throwable {
System.out.println("portable serial format");
+ boolean generateData = false;
+ //generateData = true; // set this true to generate the following input data:
Object[][] cases = {
{ mt_vv, new byte[] { // ()void
- (byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x13,
- (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x64, (byte)0x79, (byte)0x6e,
+ (byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x1b,
+ (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
+ (byte)0x67, (byte)0x2e, (byte)0x69, (byte)0x6e, (byte)0x76, (byte)0x6f, (byte)0x6b, (byte)0x65,
(byte)0x2e, (byte)0x4d, (byte)0x65, (byte)0x74, (byte)0x68, (byte)0x6f, (byte)0x64, (byte)0x54,
(byte)0x79, (byte)0x70, (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x01, (byte)0x24, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
@@ -493,8 +483,9 @@ public class MethodTypeTest {
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78,
} },
{ mt_OO, new byte[] { // (Object)Object
- (byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x13,
- (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x64, (byte)0x79, (byte)0x6e,
+ (byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x1b,
+ (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
+ (byte)0x67, (byte)0x2e, (byte)0x69, (byte)0x6e, (byte)0x76, (byte)0x6f, (byte)0x6b, (byte)0x65,
(byte)0x2e, (byte)0x4d, (byte)0x65, (byte)0x74, (byte)0x68, (byte)0x6f, (byte)0x64, (byte)0x54,
(byte)0x79, (byte)0x70, (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x01, (byte)0x24, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
@@ -509,14 +500,47 @@ public class MethodTypeTest {
(byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01,
(byte)0x71, (byte)0x00, (byte)0x7e, (byte)0x00, (byte)0x03, (byte)0x78,
} },
+ { mt_vOiSzA, new byte[] { // (Object,int,String,boolean,Object[])void
+ (byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x1b,
+ (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
+ (byte)0x67, (byte)0x2e, (byte)0x69, (byte)0x6e, (byte)0x76, (byte)0x6f, (byte)0x6b, (byte)0x65,
+ (byte)0x2e, (byte)0x4d, (byte)0x65, (byte)0x74, (byte)0x68, (byte)0x6f, (byte)0x64, (byte)0x54,
+ (byte)0x79, (byte)0x70, (byte)0x65, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x01, (byte)0x24, (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
+ (byte)0x76, (byte)0x72, (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x6f, (byte)0x69, (byte)0x64,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70, (byte)0x75, (byte)0x72, (byte)0x00,
+ (byte)0x12, (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e,
+ (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x43, (byte)0x6c, (byte)0x61,
+ (byte)0x73, (byte)0x73, (byte)0x3b, (byte)0xab, (byte)0x16, (byte)0xd7, (byte)0xae, (byte)0xcb,
+ (byte)0xcd, (byte)0x5a, (byte)0x99, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x05, (byte)0x76, (byte)0x72, (byte)0x00, (byte)0x10,
+ (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
+ (byte)0x67, (byte)0x2e, (byte)0x4f, (byte)0x62, (byte)0x6a, (byte)0x65, (byte)0x63, (byte)0x74,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70, (byte)0x76, (byte)0x72, (byte)0x00,
+ (byte)0x03, (byte)0x69, (byte)0x6e, (byte)0x74, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78,
+ (byte)0x70, (byte)0x76, (byte)0x72, (byte)0x00, (byte)0x10, (byte)0x6a, (byte)0x61, (byte)0x76,
+ (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x53,
+ (byte)0x74, (byte)0x72, (byte)0x69, (byte)0x6e, (byte)0x67, (byte)0xa0, (byte)0xf0, (byte)0xa4,
+ (byte)0x38, (byte)0x7a, (byte)0x3b, (byte)0xb3, (byte)0x42, (byte)0x02, (byte)0x00, (byte)0x00,
+ (byte)0x78, (byte)0x70, (byte)0x76, (byte)0x72, (byte)0x00, (byte)0x07, (byte)0x62, (byte)0x6f,
+ (byte)0x6f, (byte)0x6c, (byte)0x65, (byte)0x61, (byte)0x6e, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+ (byte)0x78, (byte)0x70, (byte)0x76, (byte)0x72, (byte)0x00, (byte)0x13, (byte)0x5b, (byte)0x4c,
+ (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
+ (byte)0x67, (byte)0x2e, (byte)0x4f, (byte)0x62, (byte)0x6a, (byte)0x65, (byte)0x63, (byte)0x74,
+ (byte)0x3b, (byte)0x90, (byte)0xce, (byte)0x58, (byte)0x9f, (byte)0x10, (byte)0x73, (byte)0x29,
+ (byte)0x6c, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70, (byte)0x78,
+ } },
};
- boolean generateData = false;
- //generateData = true;
for (Object[] c : cases) {
MethodType mt = (MethodType) c[0];
System.out.println("deserialize "+mt);
byte[] wire = (byte[]) c[1];
if (generateData) {
+ System.out.println("");
wire = writeSerial(mt);
final String INDENT = " ";
System.out.print("{ // "+mt);
@@ -528,6 +552,7 @@ public class MethodTypeTest {
}
System.out.println();
System.out.println(INDENT+"}");
+ System.out.println(" ");
System.out.flush();
}
Object decode;
diff --git a/jdk/test/java/dyn/indify/Indify.java b/jdk/test/java/lang/invoke/indify/Indify.java
similarity index 98%
rename from jdk/test/java/dyn/indify/Indify.java
rename to jdk/test/java/lang/invoke/indify/Indify.java
index ba24b79a9d9..ac0485a5ebc 100644
--- a/jdk/test/java/dyn/indify/Indify.java
+++ b/jdk/test/java/lang/invoke/indify/Indify.java
@@ -47,9 +47,9 @@ import java.util.regex.*;
* and {@code CONSTANT_MethodType} "ldc" instructions.
* The stereotyped code must create method types by calls to {@code methodType} or
* {@code fromMethodDescriptorString}. The "lookup" argument must be created
- * by calls to {@code java.dyn.MethodHandles#lookup MethodHandles.lookup}.
+ * by calls to {@code java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
* The class and string arguments must be constant.
- * The following methods of {@code java.dyn.MethodHandle.Lookup Lookup} are
+ * The following methods of {@code java.lang.invoke.MethodHandle.Lookup Lookup} are
* allowed for method handle creation: {@code findStatic}, {@code findVirtual},
* {@code findConstructor}, {@code findSpecial},
* {@code findGetter}, {@code findSetter},
@@ -350,10 +350,15 @@ public class Indify {
}
protected Class> findClass(String name) throws ClassNotFoundException {
try {
- return transformAndLoadClass(findClassInPath(name));
+ File f = findClassInPath(name);
+ if (f != null) {
+ Class> c = transformAndLoadClass(f);
+ if (c != null) return c;
+ }
} catch (IOException ex) {
throw new ClassNotFoundException("IO error", ex);
}
+ throw new ClassNotFoundException();
}
private Class> transformAndLoadClass(File f) throws ClassNotFoundException, IOException {
if (verbose) System.err.println("Loading class from "+f);
@@ -592,7 +597,9 @@ public class Indify {
if (s.startsWith("MT_")) return 'T';
else if (s.startsWith("MH_")) return 'H';
else if (s.startsWith("INDY_")) return 'I';
- else if (s.startsWith("java/dyn/")) return 'D';
+ else if (transitionalJSR292 &&
+ s.startsWith("java/dyn/")) return 'D';
+ else if (s.startsWith("java/lang/invoke/")) return 'D';
else if (s.startsWith("java/lang/")) return 'J';
return 0;
}
@@ -605,15 +612,24 @@ public class Indify {
String descr = cf.pool.getString(CONSTANT_Utf8, n2);
String requiredType;
switch (poolMarks[(char)n1]) {
- case 'H': requiredType = "()Ljava/dyn/MethodHandle;"; break;
- case 'T': requiredType = "()Ljava/dyn/MethodType;"; break;
- case 'I': requiredType = "()Ljava/dyn/MethodHandle;"; break;
+ case 'H': requiredType = "()Ljava/lang/invoke/MethodHandle;"; break;
+ case 'T': requiredType = "()Ljava/lang/invoke/MethodType;"; break;
+ case 'I': requiredType = "()Ljava/lang/invoke/MethodHandle;"; break;
default: return 0;
}
- if (descr.equals(requiredType)) return mark;
+ if (matchType(descr, requiredType)) return mark;
return 0;
}
+ boolean matchType(String descr, String requiredType) {
+ if (descr.equals(requiredType)) return true;
+ if (transitionalJSR292) {
+ String oldType = requiredType.replace("Ljava/lang/invoke/", "Ljava/dyn/");
+ if (descr.equals(oldType)) return true;
+ }
+ return false;
+ }
+
private class JVMState {
final List stack = new ArrayList<>();
int sp() { return stack.size(); }
diff --git a/jdk/test/java/net/URI/Test.java b/jdk/test/java/net/URI/Test.java
index f0bb8da821a..3f157ea7561 100644
--- a/jdk/test/java/net/URI/Test.java
+++ b/jdk/test/java/net/URI/Test.java
@@ -23,7 +23,7 @@
/* @test
* @summary Unit test for java.net.URI
- * @bug 4464135 4505046 4503239 4438319 4991359 4866303
+ * @bug 4464135 4505046 4503239 4438319 4991359 4866303 7023363
* @author Mark Reinhold
*/
@@ -1050,6 +1050,13 @@ public class Test {
test("http://1.2.3.4.5").psa().x().z();
test("http://[1.2.3.4:5]").x().z();
test("http://1:2:3:4:5:6:7:8").psa().x().z();
+ test("http://[1.2.3.4]/").x().z();
+ test("http://[1.2.3.4/").x().z();
+ test("http://[foo]/").x().z();
+ test("http://[foo/").x().z();
+ test("s", "[foo]", "/", null, null).x().z();
+ test("s", "[foo", "/", null, null).x().z();
+ test("s", "[::foo", "/", null, null).x().z();
// Test hostnames that might initially look like IPv4 addresses
diff --git a/jdk/test/java/net/URLConnection/GetXmlContentType.java b/jdk/test/java/net/URLConnection/GetXmlContentType.java
index 5c3282d63ec..e89043a9781 100644
--- a/jdk/test/java/net/URLConnection/GetXmlContentType.java
+++ b/jdk/test/java/net/URLConnection/GetXmlContentType.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2011, 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
@@ -23,8 +23,8 @@
/*
* @test
- * @bug 4160195
- * @summary Check for correct detection of XML content type
+ * @bug 4160195 7026346
+ * @summary Check for correct detection of XML content type, including BOM streams
*/
import java.io.*;
@@ -34,6 +34,8 @@ import java.net.*;
public class GetXmlContentType {
static final String XML_MIME_TYPE = "application/xml";
+ static final String XML_HEADER = " 0)
+ throw new RuntimeException (
+ "Test failed; passed = " + passed + ", failed = " + failed);
+ }
+
+ static void contentTypeFromFile() throws Exception {
// POSITIVE tests: good data --> good result
- //
- for (int i = 0; i < goodFiles.length; i++) {
- String result = getUrlContentType (goodFiles [i]);
- if (!XML_MIME_TYPE.equals (result)) {
- System.out.println ("Wrong MIME type: "
- + goodFiles [i]
- + " --> " + result
- );
- sawError = true;
+ for (String goodFile : goodFiles) {
+ String result = getUrlContentType(goodFile);
+
+ if (!XML_MIME_TYPE.equals(result)) {
+ System.out.println("Wrong MIME type: " + goodFile + " --> " + result);
+ failed++;
+ } else {
+ passed++;
}
}
- //
// NEGATIVE tests: bad data --> correct diagnostic
- //
- for (int i = 0; i < badFiles.length; i++) {
- String result = getUrlContentType (badFiles [i]);
+ for (String badFile : badFiles) {
+ String result = getUrlContentType(badFile);
- if (XML_MIME_TYPE.equals (result)) {
- System.out.println ("Wrong MIME type: "
- + badFiles [i]
- + " --> " + result
- );
- sawError = true;
+ if (XML_MIME_TYPE.equals(result)) {
+ System.out.println("Wrong MIME type: " + badFile + " --> " + result);
+ failed++;
+ } else {
+ passed++;
}
}
-
- if (sawError)
- throw new Exception (
- "GetXmlContentType Test failed; see diagnostics.");
}
- static String getUrlContentType (String name) throws IOException {
- File file = new File(System.getProperty("test.src", "."), "xml");
- URL u = new URL ("file:"
- + file.getCanonicalPath()
- + file.separator
- + name);
- URLConnection conn = u.openConnection ();
+ static String getUrlContentType(String name) throws IOException {
+ File file = new File(System.getProperty("test.src", "."), "xml");
+ URL u = new URL("file:"
+ + file.getCanonicalPath()
+ + file.separator
+ + name);
+ URLConnection conn = u.openConnection();
- return conn.getContentType ();
+ return conn.getContentType();
}
+ static void contentTypeFromBOMStream() throws Exception {
+ final String[] encodings = new String[]
+ {"UTF-8", "UTF-16BE", "UTF-16LE", "UTF-32BE", "UTF-32LE"};
+ for (String encoding : encodings) {
+ try (InputStream is = new ByteArrayInputStream(toBOMBytes(encoding))) {
+ String mime = URLConnection.guessContentTypeFromStream(is);
+ if ( !XML_MIME_TYPE.equals(mime) ) {
+ System.out.println("Wrong MIME type: " + encoding + " --> " + mime);
+ failed++;
+ } else {
+ passed++;
+ }
+ }
+ }
+ }
+
+ static byte[] toBOMBytes(String encoding) throws Exception {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ switch (encoding) {
+ case "UTF-8" :
+ bos.write(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF });
+ break;
+ case "UTF-16BE" :
+ bos.write(new byte[] { (byte) 0xFE, (byte) 0xFF });
+ break;
+ case "UTF-16LE" :
+ bos.write(new byte[] { (byte) 0xFF, (byte) 0xFE });
+ break;
+ case "UTF-32BE" :
+ bos.write(new byte[] { (byte) 0x00, (byte) 0x00,
+ (byte) 0xFE, (byte) 0xFF });
+ break;
+ case "UTF-32LE" :
+ bos.write(new byte[] { (byte) 0xFF, (byte) 0xFE,
+ (byte) 0x00, (byte) 0x00 });
+ }
+
+ bos.write(XML_HEADER.getBytes(encoding));
+ return bos.toByteArray();
+ }
}
diff --git a/jdk/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java b/jdk/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java
index aa79e2214df..f4445bb946f 100644
--- a/jdk/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java
+++ b/jdk/test/java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java
@@ -22,7 +22,7 @@
*/
/* @test
- * @bug 4527345
+ * @bug 4527345 7026376
* @summary Unit test for DatagramChannel's multicast support
* @build MulticastSendReceiveTests NetworkConfiguration
* @run main MulticastSendReceiveTests
@@ -31,12 +31,19 @@
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.net.*;
+import static java.net.StandardProtocolFamily.*;
import java.util.*;
import java.io.IOException;
public class MulticastSendReceiveTests {
- static Random rand = new Random();
+ static final Random rand = new Random();
+
+ static final ProtocolFamily UNSPEC = new ProtocolFamily() {
+ public String name() {
+ return "UNSPEC";
+ }
+ };
/**
* Send datagram from given local address to given multicast
@@ -130,75 +137,84 @@ public class MulticastSendReceiveTests {
/**
* Exercise multicast send/receive on given group/interface
*/
- static void test(NetworkInterface nif, InetAddress group, InetAddress source)
+ static void test(ProtocolFamily family,
+ NetworkInterface nif,
+ InetAddress group,
+ InetAddress source)
throws IOException
{
- ProtocolFamily family = (group instanceof Inet6Address) ?
- StandardProtocolFamily.INET6 : StandardProtocolFamily.INET;
- System.out.format("create channel to %s socket\n", family.name());
- DatagramChannel dc = DatagramChannel.open(family)
- .setOption(StandardSocketOption.SO_REUSEADDR, true)
- .bind(new InetSocketAddress(0));
+ System.out.format("\nTest DatagramChannel to %s socket\n", family.name());
+ try (DatagramChannel dc = (family == UNSPEC) ?
+ DatagramChannel.open() : DatagramChannel.open(family)) {
+ dc.setOption(StandardSocketOption.SO_REUSEADDR, true)
+ .bind(new InetSocketAddress(0));
- // join group
- System.out.format("join %s @ %s\n", group.getHostAddress(),
- nif.getName());
- MembershipKey key = dc.join(group, nif);
+ // join group
+ System.out.format("join %s @ %s\n", group.getHostAddress(),
+ nif.getName());
+ MembershipKey key;
+ try {
+ key = dc.join(group, nif);
+ } catch (IllegalArgumentException iae) {
+ if (family == UNSPEC) {
+ System.out.println("Not supported");
+ return;
+ }
+ throw iae;
+ }
- // send message to group
- int port = ((InetSocketAddress)dc.getLocalAddress()).getPort();
- int id = sendDatagram(source, nif, group, port);
+ // send message to group
+ int port = ((InetSocketAddress)dc.getLocalAddress()).getPort();
+ int id = sendDatagram(source, nif, group, port);
- // receive message and check id matches
- receiveDatagram(dc, source, id);
-
- // exclude-mode filtering
-
- try {
- System.out.format("block %s\n", source.getHostAddress());
-
- // may throw UOE
- key.block(source);
- id = sendDatagram(source, nif, group, port);
- receiveDatagram(dc, null, id);
-
- // unblock source, send message, message should be received
- System.out.format("unblock %s\n", source.getHostAddress());
- key.unblock(source);
- id = sendDatagram(source, nif, group, port);
+ // receive message and check id matches
receiveDatagram(dc, source, id);
- } catch (UnsupportedOperationException x) {
- System.out.println("Exclude-mode filtering not supported!");
- }
- key.drop();
+ // exclude-mode filtering
- // include-mode filtering
+ try {
+ System.out.format("block %s\n", source.getHostAddress());
- InetAddress bogus = (group instanceof Inet6Address) ?
- InetAddress.getByName("fe80::1234") :
- InetAddress.getByName("1.2.3.4");
- System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
- nif.getName(), bogus.getHostAddress());
- try {
- // may throw UOE
- key = dc.join(group, nif, bogus);
+ // may throw UOE
+ key.block(source);
+ id = sendDatagram(source, nif, group, port);
+ receiveDatagram(dc, null, id);
- id = sendDatagram(source, nif, group, port);
- receiveDatagram(dc, null, id);
+ // unblock source, send message, message should be received
+ System.out.format("unblock %s\n", source.getHostAddress());
+ key.unblock(source);
+ id = sendDatagram(source, nif, group, port);
+ receiveDatagram(dc, source, id);
+ } catch (UnsupportedOperationException x) {
+ System.out.println("Exclude-mode filtering not supported!");
+ }
+ key.drop();
+
+ // include-mode filtering
+
+ InetAddress bogus = (group instanceof Inet6Address) ?
+ InetAddress.getByName("fe80::1234") :
+ InetAddress.getByName("1.2.3.4");
System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
- nif.getName(), source.getHostAddress());
- key = dc.join(group, nif, source);
+ nif.getName(), bogus.getHostAddress());
+ try {
+ // may throw UOE
+ key = dc.join(group, nif, bogus);
- id = sendDatagram(source, nif, group, port);
- receiveDatagram(dc, source, id);
- } catch (UnsupportedOperationException x) {
- System.out.println("Include-mode filtering not supported!");
+ id = sendDatagram(source, nif, group, port);
+ receiveDatagram(dc, null, id);
+
+ System.out.format("join %s @ %s only-source %s\n", group.getHostAddress(),
+ nif.getName(), source.getHostAddress());
+ key = dc.join(group, nif, source);
+
+ id = sendDatagram(source, nif, group, port);
+ receiveDatagram(dc, source, id);
+ } catch (UnsupportedOperationException x) {
+ System.out.println("Include-mode filtering not supported!");
+ }
}
-
- // done
- dc.close();
}
public static void main(String[] args) throws IOException {
@@ -210,12 +226,14 @@ public class MulticastSendReceiveTests {
for (NetworkInterface nif: config.ip4Interfaces()) {
InetAddress source = config.ip4Addresses(nif).iterator().next();
- test(nif, ip4Group, source);
+ test(INET, nif, ip4Group, source);
+ test(UNSPEC, nif, ip4Group, source);
}
for (NetworkInterface nif: config.ip6Interfaces()) {
InetAddress source = config.ip6Addresses(nif).iterator().next();
- test(nif, ip6Group, source);
+ test(INET6, nif, ip6Group, source);
+ test(UNSPEC, nif, ip6Group, source);
}
}
}
diff --git a/jdk/test/java/nio/file/Files/FileAttributes.java b/jdk/test/java/nio/file/Files/FileAttributes.java
index bd799dc6b1e..d8aea7fe3ba 100644
--- a/jdk/test/java/nio/file/Files/FileAttributes.java
+++ b/jdk/test/java/nio/file/Files/FileAttributes.java
@@ -22,7 +22,7 @@
*/
/* @test
- * @bug 4313887 6838333
+ * @bug 4313887 6838333 7017446
* @summary Unit test for java.nio.file.Files
* @library ..
*/
@@ -94,12 +94,6 @@ public class FileAttributes {
assertTrue(map.size() == 2);
checkEqual(attrs.size(), map.get("size"));
checkEqual(attrs.lastModifiedTime(), map.get("lastModifiedTime"));
-
- map = Files.readAttributes(file,
- "basic:lastModifiedTime,lastAccessTime,ShouldNotExist");
- assertTrue(map.size() == 2);
- checkEqual(attrs.lastModifiedTime(), map.get("lastModifiedTime"));
- checkEqual(attrs.lastAccessTime(), map.get("lastAccessTime"));
}
// Exercise getAttribute/setAttribute/readAttributes on posix attributes
@@ -132,7 +126,7 @@ public class FileAttributes {
assertTrue(map.size() >= 12);
checkEqual(attrs.permissions(), map.get("permissions")); // check one
- map = Files.readAttributes(file, "posix:size,owner,ShouldNotExist");
+ map = Files.readAttributes(file, "posix:size,owner");
assertTrue(map.size() == 2);
checkEqual(attrs.size(), map.get("size"));
checkEqual(attrs.owner(), map.get("owner"));
@@ -155,7 +149,7 @@ public class FileAttributes {
map = Files.readAttributes(file, "unix:*");
assertTrue(map.size() >= 20);
- map = Files.readAttributes(file, "unix:size,uid,gid,ShouldNotExist");
+ map = Files.readAttributes(file, "unix:size,uid,gid");
assertTrue(map.size() == 3);
checkEqual(map.get("size"),
Files.readAttributes(file, BasicFileAttributes.class).size());
@@ -206,14 +200,65 @@ public class FileAttributes {
assertTrue(map.size() >= 13);
checkEqual(attrs.isReadOnly(), map.get("readonly")); // check one
- map = Files.readAttributes(file, "dos:size,hidden,ShouldNotExist");
+ map = Files.readAttributes(file, "dos:size,hidden");
assertTrue(map.size() == 2);
checkEqual(attrs.size(), map.get("size"));
checkEqual(attrs.isHidden(), map.get("hidden"));
}
+ static void checkBadSet(Path file, String attribute, Object value)
+ throws IOException
+ {
+ try {
+ Files.setAttribute(file, attribute, 0);
+ throw new RuntimeException("IllegalArgumentException expected");
+ } catch (IllegalArgumentException ignore) { }
+ }
+
+ static void checkBadGet(Path file, String attribute) throws IOException {
+ try {
+ Files.getAttribute(file, attribute);
+ throw new RuntimeException("IllegalArgumentException expected");
+ } catch (IllegalArgumentException ignore) { }
+ }
+
+ static void checkBadRead(Path file, String attribute) throws IOException {
+ try {
+ Files.readAttributes(file, attribute);
+ throw new RuntimeException("IllegalArgumentException expected");
+ } catch (IllegalArgumentException ignore) { }
+ }
+
static void miscTests(Path file) throws IOException {
- // NPE tests
+ // unsupported views
+ try {
+ Files.setAttribute(file, "foo:bar", 0);
+ throw new RuntimeException("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException ignore) { }
+ try {
+ Files.getAttribute(file, "foo:bar");
+ throw new RuntimeException("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException ignore) { }
+ try {
+ Files.readAttributes(file, "foo:*");
+ throw new RuntimeException("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException ignore) { }
+
+ // bad args
+ checkBadSet(file, "", 0);
+ checkBadSet(file, "basic:", 0);
+ checkBadSet(file, "basic:foobar", 0);
+ checkBadGet(file, "");
+ checkBadGet(file, "basic:");
+ checkBadGet(file, "basic:foobar");
+ checkBadGet(file, "basic:size,lastModifiedTime");
+ checkBadGet(file, "basic:*");
+ checkBadRead(file, "");
+ checkBadRead(file, "basic:");
+ checkBadRead(file, "basic:foobar");
+ checkBadRead(file, "basic:size,foobar");
+
+ // nulls
try {
Files.getAttribute(file, null);
throw new RuntimeException("NullPointerException expected");
diff --git a/jdk/test/java/nio/file/WatchService/Basic.java b/jdk/test/java/nio/file/WatchService/Basic.java
index 2869a519f37..1b4c526dbd8 100644
--- a/jdk/test/java/nio/file/WatchService/Basic.java
+++ b/jdk/test/java/nio/file/WatchService/Basic.java
@@ -22,7 +22,7 @@
*/
/* @test
- * @bug 4313887 6838333
+ * @bug 4313887 6838333 7017446
* @summary Unit test for java.nio.file.WatchService
* @library ..
* @run main/timeout=120 Basic
@@ -44,6 +44,8 @@ public class Basic {
static void checkKey(WatchKey key, Path dir) {
if (!key.isValid())
throw new RuntimeException("Key is not valid");
+ if (key.watchable() != dir)
+ throw new RuntimeException("Unexpected watchable");
}
static void takeExpectedKey(WatchService watcher, WatchKey expected) {
diff --git a/jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java b/jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java
index a6af4192234..c8c07b4d8e4 100644
--- a/jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java
+++ b/jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java
@@ -141,9 +141,6 @@ public class Basic {
map = Files.readAttributes(file, "user:*");
if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME)))
throw new RuntimeException("Unexpected attribute value");
- map = Files.readAttributes(file, "user:DoesNotExist");
- if (!map.isEmpty())
- throw new RuntimeException("Map expected to be empty");
}
static void miscTests(final Path file) throws IOException {
diff --git a/jdk/test/java/util/EnumSet/LargeEnumIteratorRemoveResilience.java b/jdk/test/java/util/EnumSet/LargeEnumIteratorRemoveResilience.java
new file mode 100644
index 00000000000..7113ba24647
--- /dev/null
+++ b/jdk/test/java/util/EnumSet/LargeEnumIteratorRemoveResilience.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2011 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.
+ */
+
+/*
+ * Portions Copyright (c) 2011 IBM Corporation
+ */
+
+/*
+ * @test
+ * @bug 7014637
+ * @summary EnumSet's iterator.remove() can be resilient to set's modification.
+ * @author Neil Richards ,
+ */
+
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class LargeEnumIteratorRemoveResilience {
+ // enum with more than 64 values
+ private static enum LargeEnum {
+ e00, e01, e02, e03, e04, e05, e06, e07,
+ e08, e09, e0A, e0B, e0C, e0D, e0E, e0F,
+ e10, e11, e12, e13, e14, e15, e16, e17,
+ e18, e19, e1A, e1B, e1C, e1D, e1E, e1F,
+ e20, e21, e22, e23, e24, e25, e26, e27,
+ e28, e29, e2A, e2B, e2C, e2D, e2E, e2F,
+ e30, e31, e32, e33, e34, e35, e36, e37,
+ e38, e39, e3A, e3B, e3C, e3D, e3E, e3F,
+ e40, e41, e42, e43, e44, e45, e46, e47,
+ e48, e49, e4A, e4B, e4C, e4D, e4E, e4F,
+ }
+
+ public static void main(final String[] args) throws Exception {
+ final Set set = EnumSet.noneOf(LargeEnum.class);
+
+ set.add(LargeEnum.e2D);
+ set.add(LargeEnum.e42);
+
+ final Iterator iterator = set.iterator();
+
+ int size = set.size();
+ LargeEnum element = iterator.next();
+
+ iterator.remove();
+ checkSetAfterRemoval(set, size, element);
+
+ size = set.size();
+ element = iterator.next();
+
+ set.remove(element);
+ checkSetAfterRemoval(set, size, element);
+
+ // The Java API declares that the behaviour here - to call
+ // iterator.remove() after the underlying collection has been
+ // modified - is "unspecified".
+ // However, in the case of iterators for EnumSet, it is easy to
+ // implement their remove() operation such that the set is
+ // unmodified if it is called for an element that has already been
+ // removed from the set - this being the naturally "resilient"
+ // behaviour.
+ iterator.remove();
+ checkSetAfterRemoval(set, size, element);
+ }
+
+ private static void checkSetAfterRemoval(final Set set,
+ final int origSize, final LargeEnum removedElement)
+ throws Exception {
+ if (set.size() != (origSize - 1)) {
+ throw new Exception("Test FAILED: Unexpected set size after removal; expected '" + (origSize - 1) + "' but found '" + set.size() + "'");
+ }
+ if (set.contains(removedElement)) {
+ throw new Exception("Test FAILED: Element returned from iterator unexpectedly still in set after removal.");
+ }
+ }
+}
diff --git a/jdk/test/java/util/EnumSet/SmallEnumIteratorRemoveResilience.java b/jdk/test/java/util/EnumSet/SmallEnumIteratorRemoveResilience.java
new file mode 100644
index 00000000000..e813a5cad3f
--- /dev/null
+++ b/jdk/test/java/util/EnumSet/SmallEnumIteratorRemoveResilience.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2011 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.
+ */
+
+/*
+ * Portions Copyright (c) 2011 IBM Corporation
+ */
+
+/*
+ * @test
+ * @bug 7014637
+ * @summary EnumSet's iterator.remove() can be resilient to set's modification.
+ * @author Neil Richards ,
+ */
+
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class SmallEnumIteratorRemoveResilience {
+ // enum with less than 64 values
+ private static enum SmallEnum { e0, e1, e2 }
+
+ public static void main(final String[] args) throws Exception {
+ final Set set = EnumSet.noneOf(SmallEnum.class);
+
+ set.add(SmallEnum.e0);
+ set.add(SmallEnum.e1);
+
+ final Iterator iterator = set.iterator();
+
+ int size = set.size();
+ SmallEnum element = iterator.next();
+
+ iterator.remove();
+ checkSetAfterRemoval(set, size, element);
+
+ size = set.size();
+ element = iterator.next();
+
+ set.remove(element);
+ checkSetAfterRemoval(set, size, element);
+
+ // The Java API declares that the behaviour here - to call
+ // iterator.remove() after the underlying collection has been
+ // modified - is "unspecified".
+ // However, in the case of iterators for EnumSet, it is easy to
+ // implement their remove() operation such that the set is
+ // unmodified if it is called for an element that has already been
+ // removed from the set - this being the naturally "resilient"
+ // behaviour.
+ iterator.remove();
+ checkSetAfterRemoval(set, size, element);
+ }
+
+ private static void checkSetAfterRemoval(final Set set,
+ final int origSize, final SmallEnum removedElement)
+ throws Exception {
+ if (set.size() != (origSize - 1)) {
+ throw new Exception("Test FAILED: Unexpected set size after removal; expected '" + (origSize - 1) + "' but found '" + set.size() + "'");
+ }
+ if (set.contains(removedElement)) {
+ throw new Exception("Test FAILED: Element returned from iterator unexpectedly still in set after removal.");
+ }
+ }
+}
diff --git a/jdk/test/java/util/Locale/LocaleEnhanceTest.java b/jdk/test/java/util/Locale/LocaleEnhanceTest.java
index 0ee6ed24dca..23445d5afc0 100644
--- a/jdk/test/java/util/Locale/LocaleEnhanceTest.java
+++ b/jdk/test/java/util/Locale/LocaleEnhanceTest.java
@@ -43,7 +43,7 @@ import java.util.Set;
/**
* @test
- * @bug 6875847
+ * @bug 6875847 6992272 7002320 7015500 7023613
* @summary test API changes to Locale
*/
public class LocaleEnhanceTest extends LocaleTestFmwk {
@@ -83,7 +83,7 @@ public class LocaleEnhanceTest extends LocaleTestFmwk {
"en-Latn-US-NewYork", "en_US_NewYork_#Latn",
"en-Latn-US", "en_US_#Latn",
"en-Latn-NewYork", "en__NewYork_#Latn", // double underscore
- "en-Latn", "en_#Latn",
+ "en-Latn", "en__#Latn", // double underscore
"en-US-NewYork", "en_US_NewYork",
"en-US", "en_US",
"en-NewYork", "en__NewYork", // double underscore
@@ -1259,6 +1259,22 @@ public class LocaleEnhanceTest extends LocaleTestFmwk {
}
}
+ public void testBug7023613() {
+ String[][] testdata = {
+ {"en-Latn", "en__#Latn"},
+ {"en-u-ca-japanese", "en__#u-ca-japanese"},
+ };
+
+ for (String[] data : testdata) {
+ String in = data[0];
+ String expected = (data.length == 1) ? data[0] : data[1];
+
+ Locale loc = Locale.forLanguageTag(in);
+ String out = loc.toString();
+ assertEquals("Empty country field with non-empty script/extension with input: " + in, expected, out);
+ }
+ }
+
///
/// utility asserts
///
diff --git a/jdk/test/java/util/TreeMap/EmptyMapAndNulls.java b/jdk/test/java/util/TreeMap/EmptyMapAndNulls.java
new file mode 100644
index 00000000000..1642f74f1bc
--- /dev/null
+++ b/jdk/test/java/util/TreeMap/EmptyMapAndNulls.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2011, 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 5045147
+ * @summary Test handling of null with empty Map
+ * @author Mike Duigou
+ */
+
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+import java.lang.reflect.*;
+
+public class EmptyMapAndNulls {
+
+ @SuppressWarnings("rawtypes")
+ static void realMain(String[] args) throws Throwable {
+ // No comparator
+ Map comparable = new TreeMap<>();
+
+ // insert null into empty map (5045147 failure)
+ try {
+ comparable.put(null, "anything");
+ fail("null shouldn't be accepted");
+ } catch (NullPointerException failed) {
+ pass();
+ }
+
+ // insert non-null into empty map
+ try {
+ comparable.put("test", "anything");
+ pass();
+ } catch (NullPointerException failed) {
+ fail();
+ }
+
+ // insert null into non-empty map
+ try {
+ comparable.put(null, "anything");
+ fail("null shouldn't be accepted");
+ } catch (NullPointerException failed) {
+ pass();
+ }
+
+ // Comparator (String.CASE_INSENSITIVE_ORDER). Intentionally a raw type.
+ Map comparator = new TreeMap(String.CASE_INSENSITIVE_ORDER);
+
+ // insert null into empty map (5045147 failure)
+ try {
+ comparator.put(null, "anything");
+ fail("null shouldn't be accepted");
+ } catch (NullPointerException failed) {
+ pass();
+ }
+
+ // insert non-null into empty map
+ try {
+ comparator.put("test", "anything");
+ pass();
+ } catch (NullPointerException failed) {
+ fail();
+ }
+
+ // insert null into non-empty map
+ try {
+ comparator.put(null, "anything");
+ fail("null shouldn't be accepted");
+ } catch (NullPointerException failed) {
+ pass();
+ }
+
+ comparator.clear();
+
+ // insert non-String into empty map (5045147 failure)
+ try {
+ comparator.put(new Object(), "anything");
+ fail("Object shouldn't be accepted");
+ } catch (ClassCastException failed) {
+ pass();
+ }
+
+ }
+
+ //--------------------- Infrastructure ---------------------------
+ static volatile int passed = 0, failed = 0;
+ static void pass() {passed++;}
+ static void fail() {failed++; Thread.dumpStack();}
+ static void fail(String msg) {System.out.println(msg); fail();}
+ static void unexpected(Throwable t) {failed++; t.printStackTrace();}
+ static void check(boolean cond) {if (cond) pass(); else fail();}
+ static void equal(Object x, Object y) {
+ if (x == null ? y == null : x.equals(y)) pass();
+ else fail(x + " not equal to " + y);}
+ public static void main(String[] args) throws Throwable {
+ try {realMain(args);} catch (Throwable t) {unexpected(t);}
+ System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+ if (failed > 0) throw new AssertionError("Some tests failed");}
+}
diff --git a/jdk/test/javax/script/GetInterfaceTest.java b/jdk/test/javax/script/GetInterfaceTest.java
new file mode 100644
index 00000000000..d780a6db08b
--- /dev/null
+++ b/jdk/test/javax/script/GetInterfaceTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011, 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 6960211
+ * @summary JavaScript engine allows creation of interface although methods not available.
+ */
+
+import javax.script.*;
+
+public class GetInterfaceTest {
+ public static void main(String[] args) throws Exception {
+ ScriptEngineManager manager = new ScriptEngineManager();
+ ScriptEngine engine = manager.getEngineByName("js");
+
+ if (engine == null) {
+ System.out.println("Warning: No engine engine found; test vacuously passes.");
+ return;
+ }
+
+ // don't define any function.
+ engine.eval("");
+
+ Runnable runnable = ((Invocable)engine).getInterface(Runnable.class);
+ if (runnable != null) {
+ throw new RuntimeException("runnable is not null!");
+ }
+
+ // now define "run"
+ engine.eval("function run() { println('this is run function'); }");
+ runnable = ((Invocable)engine).getInterface(Runnable.class);
+ // should not return null now!
+ runnable.run();
+
+ // define only one method of "Foo2"
+ engine.eval("function bar() { println('bar function'); }");
+ Foo2 foo2 = ((Invocable)engine).getInterface(Foo2.class);
+ if (foo2 != null) {
+ throw new RuntimeException("foo2 is not null!");
+ }
+
+ // now define other method of "Foo2"
+ engine.eval("function bar2() { println('bar2 function'); }");
+ foo2 = ((Invocable)engine).getInterface(Foo2.class);
+ foo2.bar();
+ foo2.bar2();
+ }
+
+ interface Foo {
+ public void bar();
+ }
+
+ interface Foo2 extends Foo {
+ public void bar2();
+ }
+}
diff --git a/jdk/test/javax/swing/JOptionPane/6464022/bug6464022.java b/jdk/test/javax/swing/JOptionPane/6464022/bug6464022.java
new file mode 100644
index 00000000000..9554ae9828e
--- /dev/null
+++ b/jdk/test/javax/swing/JOptionPane/6464022/bug6464022.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2011, 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 6464022
+ * @summary Memory leak in JOptionPane.createDialog
+ * @author Pavel Porvatov
+ * @library ../../regtesthelpers
+ * @build Util
+ * @run main bug6464022
+ */
+
+import javax.swing.*;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+public class bug6464022 {
+ private static JOptionPane pane;
+
+ public static void main(String[] args) throws Exception {
+ final List> references = new ArrayList>();
+
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ pane = new JOptionPane(null, JOptionPane.UNDEFINED_CONDITION);
+
+ for (int i = 0; i < 10; i++) {
+ JDialog dialog = pane.createDialog(null, "Test " + i);
+
+ references.add(new WeakReference(dialog));
+
+ dialog.dispose();
+
+ System.out.println("Disposing Dialog:" + dialog.hashCode());
+ }
+ }
+ });
+
+ Util.generateOOME();
+
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ int allocatedCount = 0;
+
+ for (WeakReference ref : references) {
+ if (ref.get() != null) {
+ allocatedCount++;
+
+ System.out.println(ref.get().hashCode() + " is still allocated");
+ }
+ }
+
+ if (allocatedCount > 0) {
+ throw new RuntimeException("Some dialogs still exist in memory. Test failed");
+ } else {
+ System.out.println("All dialogs were GCed. Test passed.");
+ }
+ }
+ });
+ }
+}
diff --git a/jdk/test/javax/swing/UIDefaults/6795356/bug6795356.java b/jdk/test/javax/swing/UIDefaults/6795356/bug6795356.java
index 781f57d3872..698dc00e22f 100644
--- a/jdk/test/javax/swing/UIDefaults/6795356/bug6795356.java
+++ b/jdk/test/javax/swing/UIDefaults/6795356/bug6795356.java
@@ -26,6 +26,8 @@
* @bug 6795356
* @summary Leak caused by javax.swing.UIDefaults.ProxyLazyValue.acc
* @author Alexander Potochkin
+ * @library ../../regtesthelpers
+ * @build Util
* @run main bug6795356
*/
@@ -58,43 +60,11 @@ public class bug6795356 {
weakRef = new WeakReference(domain);
domain = null;
- // Generate OutOfMemory and check the weak ref
- generateOOME();
+ Util.generateOOME();
if (weakRef.get() != null) {
throw new RuntimeException("Memory leak found!");
}
System.out.println("Test passed");
}
-
- static void generateOOME() {
- List bigLeak = new LinkedList();
- boolean oome = false;
- System.out.print("Filling the heap");
- try {
- for(int i = 0; true ; i++) {
- // Now, use up all RAM
- bigLeak.add(new byte[1024 * 1024]);
- System.out.print(".");
-
- // Give the GC a change at that weakref
- if (i % 10 == 0) {
- System.gc();
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- } catch (OutOfMemoryError e) {
- bigLeak = null;
- oome = true;
- }
- System.out.println("");
- if (!oome) {
- throw new RuntimeException("Problem with test case - never got OOME");
- }
- System.out.println("Got OOME");
- }
}
diff --git a/jdk/test/javax/swing/regtesthelpers/Util.java b/jdk/test/javax/swing/regtesthelpers/Util.java
index 5da14b9396a..76217ae8687 100644
--- a/jdk/test/javax/swing/regtesthelpers/Util.java
+++ b/jdk/test/javax/swing/regtesthelpers/Util.java
@@ -24,6 +24,8 @@
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
+import java.util.LinkedList;
+import java.util.List;
/**
* This class contains utilities useful for regression testing.
@@ -72,4 +74,46 @@ public class Util {
return true;
}
+
+ /**
+ * Fills the heap until OutOfMemoryError occurs. This method is useful for
+ * WeakReferences removing.
+ */
+ public static void generateOOME() {
+ List bigLeak = new LinkedList();
+
+ boolean oome = false;
+
+ System.out.print("Filling the heap");
+
+ try {
+ for(int i = 0; true ; i++) {
+ // Now, use up all RAM
+ bigLeak.add(new byte[1024 * 1024]);
+
+ System.out.print(".");
+
+ // Give the GC a change at that weakref
+ if (i % 10 == 0) {
+ System.gc();
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ } catch (OutOfMemoryError e) {
+ bigLeak = null;
+ oome = true;
+ }
+
+ System.out.println("");
+
+ if (!oome) {
+ throw new RuntimeException("Problem with test case - never got OOME");
+ }
+
+ System.out.println("Got OOME");
+ }
}
diff --git a/jdk/test/sun/java2d/pipe/Test7027667.java b/jdk/test/sun/java2d/pipe/Test7027667.java
new file mode 100644
index 00000000000..08f478f60b1
--- /dev/null
+++ b/jdk/test/sun/java2d/pipe/Test7027667.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2011, 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 7027667, 7023591
+ *
+ * @summary Verifies that aa clipped rectangles are drawn, not filled.
+ *
+ * @run main Test7027667
+ */
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+import static java.awt.RenderingHints.*;
+
+public class Test7027667 {
+ public static void main(String[] args) throws Exception {
+ BufferedImage bImg = new BufferedImage(512, 512, BufferedImage.TYPE_INT_RGB);
+ Graphics2D g2d = (Graphics2D) bImg.getGraphics();
+ g2d.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
+ g2d.setClip(new Ellipse2D.Double(0, 0, 100, 100));
+ g2d.drawRect(10, 10, 100, 100);
+ if (new Color(bImg.getRGB(50, 50)).equals(Color.white)) {
+ throw new Exception("Rectangle should be drawn, not filled");
+ }
+ }
+}
diff --git a/jdk/test/sun/java2d/pisces/Renderer/Test7019861.java b/jdk/test/sun/java2d/pisces/Renderer/Test7019861.java
new file mode 100644
index 00000000000..7c262b961cf
--- /dev/null
+++ b/jdk/test/sun/java2d/pisces/Renderer/Test7019861.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2011, 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 7019861
+ *
+ * @summary Verifies that the last scanline isn't skipped when doing
+ * antialiased rendering.
+ *
+ * @run main Test7019861
+ */
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.geom.Path2D;
+import java.awt.image.BufferedImage;
+import java.util.Arrays;
+
+import static java.awt.RenderingHints.*;
+
+public class Test7019861 {
+
+ public static void main(String[] argv) throws Exception {
+ BufferedImage im = getWhiteImage(30, 30);
+ Graphics2D g2 = (Graphics2D)im.getGraphics();
+ g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
+ g2.setRenderingHint(KEY_STROKE_CONTROL, VALUE_STROKE_PURE);
+ g2.setStroke(new BasicStroke(10, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+ g2.setBackground(Color.white);
+ g2.setColor(Color.black);
+
+ Path2D p = getPath(0, 0, 20);
+ g2.draw(p);
+
+ if (!(new Color(im.getRGB(20, 19))).equals(Color.black)) {
+ throw new Exception("This pixel should be black");
+ }
+ }
+
+ private static Path2D getPath(int x, int y, int len) {
+ Path2D p = new Path2D.Double();
+ p.moveTo(x, y);
+ p.quadTo(x + len, y, x + len, y + len);
+ return p;
+ }
+
+ private static BufferedImage getWhiteImage(int w, int h) {
+ BufferedImage ret = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ final int[] white = new int[w * h];
+ Arrays.fill(white, 0xffffff);
+ ret.setRGB(0, 0, w, h, white, 0, w);
+ return ret;
+ }
+}
diff --git a/jdk/test/sun/nio/cs/TestIBM1364.java b/jdk/test/sun/nio/cs/TestIBM1364.java
new file mode 100644
index 00000000000..78912bdf519
--- /dev/null
+++ b/jdk/test/sun/nio/cs/TestIBM1364.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2011, 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 6803681
+ @summary Test IBM1364
+ */
+
+import java.util.Arrays;
+import java.nio.*;
+import java.nio.charset.*;
+
+public class TestIBM1364 {
+ private static String c2bNRStr = "\u00AD\u00B7\u2015\u223C\u2299\uFF5E";
+ private static byte[] c2bNRBytes = new byte[] {
+ (byte)0x0e,
+ (byte)0x41, (byte)0x48,
+ (byte)0x41, (byte)0x43,
+ (byte)0x41, (byte)0x49,
+ (byte)0x42, (byte)0xa1,
+ (byte)0x49, (byte)0x6f,
+ (byte)0x49, (byte)0x54,
+ (byte)0x0f };
+
+ // end at SO
+ private static String mixedStr = "\u008d\u008e\u0020\u3000\u3001\u71ba\u3164\u0088\ue757";
+ private static byte[] mixedBytes = new byte[] {
+ (byte)0x09,
+ (byte)0x0a,
+ (byte)0x40,
+ (byte)0x0e,
+ (byte)0x40, (byte)0x40,
+ (byte)0x41, (byte)0x41,
+ (byte)0x6c, (byte)0x45,
+ (byte)0x84, (byte)0x41,
+ (byte)0x0f,
+ (byte)0x28,
+ (byte)0x0e,
+ (byte)0xdd, (byte)0xfd,
+ (byte)0x0f };
+
+ // end at SI
+ private static String mixedStr2 = "\u008d\u008e\u0020\u3000\u3001\u71ba\u3164\u0088";
+ private static byte[] mixedBytes2 = new byte[] {
+ (byte)0x09,
+ (byte)0x0a,
+ (byte)0x40,
+ (byte)0x0e,
+ (byte)0x40, (byte)0x40,
+ (byte)0x41, (byte)0x41,
+ (byte)0x6c, (byte)0x45,
+ (byte)0x84, (byte)0x41,
+ (byte)0x0f,
+ (byte)0x28 };
+
+ private static byte[][] malformedBytes = {
+ { (byte)0x0e,
+ (byte)0x039, (byte)0x40,
+ (byte)0x0f
+ },
+ { (byte)0x0e,
+ (byte)0x039, (byte)0x42,
+ (byte)0x0f
+ },
+ { (byte)0x0e,
+ (byte)0x040, (byte)0x41,
+ (byte)0x0f
+ },
+ { (byte)0x0e,
+ (byte)0x040, (byte)0xee,
+ (byte)0x0f
+ },
+ { (byte)0x0e,
+ (byte)0x0ef, (byte)0x30,
+ (byte)0x0f
+ },
+ { (byte)0x0e,
+ (byte)0x0ff, (byte)0x41,
+ (byte)0x0f
+ }
+ };
+
+ private static byte[][] unmappedBytes = {
+ { (byte)0x0e,
+ (byte)0x06c, (byte)0x46,
+ (byte)0x0f,
+ },
+ { (byte)0x0e,
+ (byte)0x078, (byte)0x46,
+ (byte)0x0f,
+ },
+ { (byte)0x0e,
+ (byte)0x083, (byte)0xfe,
+ (byte)0x0f,
+ },
+ { (byte)0xfa },
+ { (byte)0xfe },
+ };
+
+ public static void main(String[] args) throws Exception {
+ if (!(Arrays.equals(mixedStr.getBytes("cp1364"), mixedBytes)) ||
+ !mixedStr.equals(new String(mixedBytes, "cp1364")))
+ throw new RuntimeException("cp1364 failed on mixed!");
+
+ if (!(Arrays.equals(mixedStr2.getBytes("cp1364"), mixedBytes2)) ||
+ !mixedStr2.equals(new String(mixedBytes2, "cp1364")))
+ throw new RuntimeException("cp1364 failed on mixed!");
+
+ if (!(Arrays.equals(c2bNRStr.getBytes("cp1364"), c2bNRBytes)) ||
+ c2bNRStr.equals(new String(c2bNRBytes, "cp1364")))
+ throw new RuntimeException("cp1364 failed on c2bNR!");
+
+ ByteBuffer bb = ByteBuffer.allocateDirect(mixedBytes.length);
+ bb.put(mixedBytes).flip();
+ CharBuffer cb = Charset.forName("ibm1364").decode(bb);
+ if (!mixedStr.equals(new String(cb.toString())))
+ throw new RuntimeException("cp1364 failed on direct decod()!");
+
+ bb = ByteBuffer.allocateDirect(mixedBytes2.length);
+ bb.put(mixedBytes2).flip();
+ cb = Charset.forName("ibm1364").decode(bb);
+ if (!mixedStr2.equals(new String(cb.toString())))
+ throw new RuntimeException("cp1364 failed on direct decod()!");
+
+ cb = ByteBuffer.allocateDirect(mixedStr.length() * 2).asCharBuffer();
+ cb.put(mixedStr.toCharArray()).flip();
+ bb = Charset.forName("x-ibm1364").encode(cb);
+ if (!(Arrays.equals(Arrays.copyOf(bb.array(), bb.limit()), mixedBytes)))
+ throw new RuntimeException("cp1364 failed on direct encode()!");
+
+ cb = ByteBuffer.allocateDirect(mixedStr2.length() * 2).asCharBuffer();
+ cb.put(mixedStr2.toCharArray()).flip();
+ bb = Charset.forName("x-ibm1364").encode(cb);
+ if (!(Arrays.equals(Arrays.copyOf(bb.array(), bb.limit()), mixedBytes2)))
+ throw new RuntimeException("cp1364 failed on direct encode()!");
+
+ // malformed
+ cb = CharBuffer.allocate(1024);
+ CharBuffer cbd = ByteBuffer.allocateDirect(1024).asCharBuffer();
+ CharsetDecoder dec = Charset.forName("x-ibm1364").newDecoder();
+ for (byte[] ba:malformedBytes) {
+ cb.clear();
+ dec.reset();
+ if (!dec.reset().decode(ByteBuffer.wrap(ba), cb, true).isMalformed() ||
+ !dec.reset().decode(ByteBuffer.wrap(ba), cbd, true).isMalformed())
+ throw new RuntimeException("cp1364 failed on decode()/malformed!");
+ }
+
+ //unmappable
+ for (byte[] ba:unmappedBytes) {
+ cb.clear();
+ dec.reset();
+ if (!dec.reset().decode(ByteBuffer.wrap(ba), cb, true).isUnmappable() ||
+ !dec.reset().decode(ByteBuffer.wrap(ba), cbd, true).isUnmappable())
+ throw new RuntimeException("cp1364 failed on decode()/unmappable!");
+ }
+
+ //overflow
+ cb.limit(mixedStr.length() - 1);
+ cbd.limit(mixedStr.length() - 1);
+ if (!dec.reset().decode(ByteBuffer.wrap(mixedBytes), cb, true).isOverflow() ||
+ !dec.reset().decode(ByteBuffer.wrap(mixedBytes), cbd, true).isOverflow())
+ throw new RuntimeException("cp1364 failed on decode()/overflow!");
+
+ CharsetEncoder enc = Charset.forName("x-ibm1364").newEncoder();
+ // last "0x0f" is from flush()
+ bb = ByteBuffer.allocate(mixedBytes.length - 2);
+ ByteBuffer bbd = ByteBuffer.allocateDirect(mixedBytes.length - 2);
+ if (!enc.reset()
+ .encode(CharBuffer.wrap(mixedStr.toCharArray()), bb, true)
+ .isOverflow() ||
+ !enc.reset()
+ .encode(CharBuffer.wrap(mixedStr.toCharArray()), bbd, true)
+ .isOverflow())
+ throw new RuntimeException("cp1364 failed on encode()/overflow!");
+
+ // flush() overflow
+ bb = ByteBuffer.allocate(mixedBytes.length - 1);
+ bbd = ByteBuffer.allocateDirect(mixedBytes.length - 1);
+
+ enc.reset().encode(CharBuffer.wrap(mixedStr.toCharArray()), bb, true);
+ enc.reset().encode(CharBuffer.wrap(mixedStr.toCharArray()), bbd, true);
+
+ if (!enc.flush(bb).isOverflow() ||
+ !enc.flush(bbd).isOverflow())
+ throw new RuntimeException("cp1364 failed on encode()/flush()/overflow!");
+ }
+}
diff --git a/jdk/test/sun/security/mscapi/access.policy b/jdk/test/sun/security/mscapi/access.policy
index 27e6692027c..22bf290bd8f 100644
--- a/jdk/test/sun/security/mscapi/access.policy
+++ b/jdk/test/sun/security/mscapi/access.policy
@@ -3,7 +3,7 @@ grant {
permission java.lang.RuntimePermission
"accessClassInPackage.sun.*";
- permission java.lang.RuntimePermission "loadLibrary.sunmscapi";
+ permission java.lang.RuntimePermission "loadLibrary.*";
permission java.util.PropertyPermission "os.arch", "read";
diff --git a/jdk/test/sun/security/mscapi/noaccess.policy b/jdk/test/sun/security/mscapi/noaccess.policy
index 8cda681cfed..e4260cf5070 100644
--- a/jdk/test/sun/security/mscapi/noaccess.policy
+++ b/jdk/test/sun/security/mscapi/noaccess.policy
@@ -3,7 +3,7 @@ grant {
permission java.lang.RuntimePermission
"accessClassInPackage.sun.*";
- permission java.lang.RuntimePermission "loadLibrary.sunmscapi";
+ permission java.lang.RuntimePermission "loadLibrary.*";
permission java.util.PropertyPermission "os.arch", "read";
diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/GetInstance.java b/jdk/test/sun/security/ssl/javax/net/ssl/GetInstance.java
index dcfb98b48c4..2ffdad9ac02 100644
--- a/jdk/test/sun/security/ssl/javax/net/ssl/GetInstance.java
+++ b/jdk/test/sun/security/ssl/javax/net/ssl/GetInstance.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2011, 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
@@ -23,8 +23,9 @@
/*
* @test
- * @bug 4898428
+ * @bug 4898428 7022855
* @summary verify getInstance() works using Provider.getService()
+ * Export "PKIX" as the standard algorithm name of KeyManagerFactory
* @author Andreas Sterbenz
*/
@@ -61,6 +62,20 @@ public class GetInstance {
kmf = KeyManagerFactory.getInstance("SunX509", p);
same(p, kmf.getProvider());
+ kmf = KeyManagerFactory.getInstance("NewSunX509");
+ same(p, kmf.getProvider());
+ kmf = KeyManagerFactory.getInstance("NewSunX509", "SunJSSE");
+ same(p, kmf.getProvider());
+ kmf = KeyManagerFactory.getInstance("NewSunX509", p);
+ same(p, kmf.getProvider());
+
+ kmf = KeyManagerFactory.getInstance("PKIX");
+ same(p, kmf.getProvider());
+ kmf = KeyManagerFactory.getInstance("PKIX", "SunJSSE");
+ same(p, kmf.getProvider());
+ kmf = KeyManagerFactory.getInstance("PKIX", p);
+ same(p, kmf.getProvider());
+
TrustManagerFactory tmf;
tmf = TrustManagerFactory.getInstance("SunX509");
same(p, tmf.getProvider());
@@ -69,6 +84,34 @@ public class GetInstance {
tmf = TrustManagerFactory.getInstance("SunX509", p);
same(p, tmf.getProvider());
+ tmf = TrustManagerFactory.getInstance("PKIX");
+ same(p, tmf.getProvider());
+ tmf = TrustManagerFactory.getInstance("PKIX", "SunJSSE");
+ same(p, tmf.getProvider());
+ tmf = TrustManagerFactory.getInstance("PKIX", p);
+ same(p, tmf.getProvider());
+
+ tmf = TrustManagerFactory.getInstance("SunPKIX");
+ same(p, tmf.getProvider());
+ tmf = TrustManagerFactory.getInstance("SunPKIX", "SunJSSE");
+ same(p, tmf.getProvider());
+ tmf = TrustManagerFactory.getInstance("SunPKIX", p);
+ same(p, tmf.getProvider());
+
+ tmf = TrustManagerFactory.getInstance("X509");
+ same(p, tmf.getProvider());
+ tmf = TrustManagerFactory.getInstance("X509", "SunJSSE");
+ same(p, tmf.getProvider());
+ tmf = TrustManagerFactory.getInstance("X509", p);
+ same(p, tmf.getProvider());
+
+ tmf = TrustManagerFactory.getInstance("X.509");
+ same(p, tmf.getProvider());
+ tmf = TrustManagerFactory.getInstance("X.509", "SunJSSE");
+ same(p, tmf.getProvider());
+ tmf = TrustManagerFactory.getInstance("X.509", p);
+ same(p, tmf.getProvider());
+
testComSun();
long stop = System.currentTimeMillis();
diff --git a/jdk/test/tools/launcher/MiscTests.java b/jdk/test/tools/launcher/MiscTests.java
index 654a56a01f4..1d7fcf9514b 100644
--- a/jdk/test/tools/launcher/MiscTests.java
+++ b/jdk/test/tools/launcher/MiscTests.java
@@ -23,8 +23,8 @@
/*
* @test
- * @bug 6856415 6981001
- * @summary Miscellaneous tests, Exceptions, EnsureJRE etc.
+ * @bug 6856415
+ * @summary Miscellaneous tests, Exceptions
* @compile -XDignore.symbol.file MiscTests.java TestHelper.java
* @run main MiscTests
*/
@@ -32,9 +32,6 @@
import java.io.File;
import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Map;
-
public class MiscTests {
@@ -67,22 +64,9 @@ public class MiscTests {
System.out.println(tr.status);
}
}
- // 6981001 : Check EnsureJreInstallation is ok, note we cannot
- // thoroughly test this function, we simply do our best.
- static void test6981001() {
- if (TestHelper.is64Bit || !TestHelper.isWindows) {
- return;
- }
- Map env = new HashMap();
- env.put("_JAVA_LAUNCHER_DEBUG", "true");
- TestHelper.TestResult tr = TestHelper.doExec(env, TestHelper.javaCmd);
- if (!tr.contains(TestHelper.JAVAHOME + "\\lib\\bundles")) {
- System.out.println(tr.status);
- }
- }
+
public static void main(String... args) {
test6856415();
- test6981001();
if (TestHelper.testExitValue != 0) {
throw new Error(TestHelper.testExitValue + " tests failed");
}