nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java
changeset 33333 0bad500ce4e0
parent 33331 273e6a10de22
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java	Mon Oct 19 08:39:06 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java	Mon Oct 19 08:45:29 2015 +0200
@@ -89,10 +89,18 @@
 import jdk.internal.dynalink.CallSiteDescriptor;
 
 /**
- * A base class for call site descriptor implementations. Provides reconstruction of the name from the tokens,
- * as well as generally useful {@code equals}, {@code hashCode}, and {@code toString} methods. For security
- * and performance reasons, subclasses must implement {@link #lookupEquals(AbstractCallSiteDescriptor)},
+ * A base class for call site descriptor implementations. Provides
+ * reconstruction of the name from the tokens, as well as generally useful
+ * {@code equals}, {@code hashCode}, and {@code toString} methods. In order to
+ * both prevent unprivileged access to its internal {@link MethodHandles.Lookup}
+ * object, and at the same time not force privileged access to it from
+ * {@code equals}, {@code hashCode}, and {@code toString} methods, subclasses
+ * must implement {@link #lookupEquals(AbstractCallSiteDescriptor)},
  * {@link #lookupHashCode()} and {@link #lookupToString()} methods.
+ * Additionally, {@link #equalsInKind(AbstractCallSiteDescriptor)} should be
+ * overridden instead of {@link #equals(Object)} to compare descriptors in
+ * subclasses; it is only necessary if they have implementation-specific
+ * properties other than the standard name, type, and lookup.
  * @param <T> The call site descriptor subclass
  */
 public abstract class AbstractCallSiteDescriptor<T extends AbstractCallSiteDescriptor<T>> implements CallSiteDescriptor {
@@ -102,6 +110,15 @@
         return appendName(new StringBuilder(getNameLength())).toString();
     }
 
+    /**
+     * Checks if this call site descriptor is equality to another object. It is
+     * considered equal iff and only if they belong to the exact same class, and
+     * have the same name, method type, and lookup. Subclasses with additional
+     * properties should override
+     * {@link #equalsInKind(AbstractCallSiteDescriptor)} instead of this method.
+     * @param obj the object checked for equality
+     * @return true if they are equal, false otherwise
+     */
     @SuppressWarnings("unchecked")
     @Override
     public boolean equals(final Object obj) {
@@ -109,8 +126,8 @@
     }
 
     /**
-     * Returns true if this call site descriptor is equal to the passed, non-null call site descriptor of the
-     * same class.
+     * Returns true if this call site descriptor is equal to the passed,
+     * non-null call site descriptor of the same class.
      * @param csd the other call site descriptor.
      * @return true if they are equal.
      */
@@ -134,20 +151,32 @@
     }
 
     /**
-     * Returns true if this call site descriptor's lookup is equal to the other call site descriptor's lookup.
-     * Typical implementation should try to obtain the other lookup directly without going through
-     * {@link #getLookup()} (e.g. directly using the implementation) and then delegate to
+     * Returns true if this call site descriptor's lookup is equal to the other
+     * call site descriptor's lookup. Typical implementation should try to
+     * obtain the other lookup directly without going through privileged
+     * {@link #getLookup()} (e.g. by reading the field as the type system
+     * enforces that they are of the same class) and then delegate to
      * {@link #lookupsEqual(MethodHandles.Lookup, MethodHandles.Lookup)}.
      * @param other the other lookup
      * @return true if the lookups are equal
      */
     protected abstract boolean lookupEquals(T other);
 
+    /**
+     * Compares two lookup objects for value-based equality. They are considered
+     * equal if they have the same
+     * {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and
+     * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()}.
+     * @param l1 first lookup
+     * @param l2 second lookup
+     * @return true if the two lookups are equal, false otherwise.
+     */
     protected static boolean lookupsEqual(final Lookup l1, final Lookup l2) {
         if(l1 == l2) {
             return true;
-        }
-        if(l1.lookupClass() != l2.lookupClass()) {
+        } else if (l1 == null || l2 == null) {
+            return false;
+        } else if(l1.lookupClass() != l2.lookupClass()) {
             return false;
         }
         return l1.lookupModes() == l2.lookupModes();
@@ -164,14 +193,24 @@
     }
 
     /**
-     * Return the hash code of this call site descriptor's {@link Lookup} object. Typical
-     * implementation should delegate to {@link #lookupHashCode(MethodHandles.Lookup)}.
-     * @return the hash code of this call site descriptor's {@link Lookup} object.
+     * Return the hash code of this call site descriptor's {@link Lookup}
+     * object. Typical implementation should delegate to
+     * {@link #lookupHashCode(MethodHandles.Lookup)}.
+     * @return the hash code of this call site descriptor's {@link Lookup}
+     * object.
      */
     protected abstract int lookupHashCode();
 
+    /**
+     * Returns a value-based hash code for the passed lookup object. It is
+     * based on the lookup object's
+     * {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and
+     * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()} values.
+     * @param lookup the lookup object.
+     * @return a hash code for the object. Returns 0 for null.
+     */
     protected static int lookupHashCode(final Lookup lookup) {
-        return lookup.lookupClass().hashCode() + 31 * lookup.lookupModes();
+        return lookup != null ? lookup.lookupClass().hashCode() + 31 * lookup.lookupModes() : 0;
     }
 
     @Override
@@ -183,9 +222,11 @@
     }
 
     /**
-     * Return a string representation of this call site descriptor's {@link Lookup} object. Typically will
-     * return {@link Lookup#toString()}.
-     * @return a string representation of this call site descriptor's {@link Lookup} object.
+     * Return a string representation of this call site descriptor's
+     * {@link Lookup} object. Typically will return
+     * {@link java.lang.invoke.MethodHandles.Lookup#toString()}.
+     * @return a string representation of this call site descriptor's
+     * {@link Lookup} object.
      */
     protected abstract String lookupToString();