() {
+ 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
*
* @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.Long | the indexed long value |
* CONSTANT_Float | java.lang.Float | the indexed float value |
* CONSTANT_Double | java.lang.Double | the indexed double value |
- * CONSTANT_MethodHandle | java.dyn.MethodHandle | the indexed method handle constant |
- * CONSTANT_MethodType | java.dyn.MethodType | the indexed method type constant |
+ * CONSTANT_MethodHandle | java.lang.invoke.MethodHandle | the indexed method handle constant |
+ * CONSTANT_MethodType | java.lang.invoke.MethodType | the 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