src/java.base/share/classes/java/lang/invoke/ConstantGroup.java
changeset 48826 c4d9d1b08e2e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/ConstantGroup.java	Fri Sep 08 10:46:46 2017 -0700
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.function.IntFunction;
+
+/**
+ * An ordered sequence of constants, some of which may not yet
+ * be present.  This type is used by {@link BootstrapCallInfo}
+ * to represent the sequence of bootstrap arguments associated
+ * with a bootstrap method, without forcing their immediate
+ * resolution.
+ * <p>
+ * If you use the
+ * {@linkplain ConstantGroup#get(int) simple get method},
+ * the constant will be resolved, if this has not already
+ * happened.  An occasional side effect of resolution is a
+ * {@code LinkageError}, which happens if the system
+ * could not resolve the constant in question.
+ * <p>
+ * In order to peek at a constant without necessarily
+ * resolving it, use the
+ * {@linkplain ConstantGroup#get(int,Object)
+ * non-throwing get method}.
+ * This method will never throw a resolution error.
+ * Instead, if the resolution would result in an error,
+ * or if the implementation elects not to attempt
+ * resolution at this point, then the method will
+ * return the user-supplied sentinel value.
+ * <p>
+ * To iterate through the constants, resolving as you go,
+ * use the iterator provided on the {@link List}-typed view.
+ * If you supply a sentinel, resolution will be suppressed.
+ * <p>
+ * Typically the constant is drawn from a constant pool entry
+ * in the virtual machine. Constant pool entries undergo a
+ * one-time state transition from unresolved to resolved,
+ * with a permanently recorded result.  Usually that result
+ * is the desired constant value, but it may also be an error.
+ * In any case, the results displayed by a {@code ConstantGroup}
+ * are stable in the same way.  If a query to a particular
+ * constant in a {@code ConstantGroup} throws an exception once,
+ * it will throw the same kind of exception forever after.
+ * If the query returns a constant value once, it will return
+ * the same value forever after.
+ * <p>
+ * The only possible change in the status of a constant is
+ * from the unresolved to the resolved state, and that
+ * happens exactly once.  A constant will never revert to
+ * an unlinked state.  However, from the point of view of
+ * this interface, constants may appear to spontaneously
+ * resolve.  This is so because constant pools are global
+ * structures shared across threads, and because
+ * prefetching of some constants may occur, there are no
+ * strong guarantees when the virtual machine may resolve
+ * constants.
+ * <p>
+ * When choosing sentinel values, be aware that a constant
+ * pool which has {@code CONSTANT_Dynamic} entries
+ * can contain potentially any representable value,
+ * and arbitrary implementations of {@code ConstantGroup}
+ * are also free to produce arbitrary values.
+ * This means some obvious choices for sentinel values,
+ * such as {@code null}, may sometimes fail to distinguish
+ * a resolved from an unresolved constant in the group.
+ * The most reliable sentinel is a privately created object,
+ * or perhaps the {@code ConstantGroup} itself.
+ * @since 1.10
+ */
+// public
+interface ConstantGroup {
+    /// Access
+
+    /**
+     * Returns the number of constants in this group.
+     * This value never changes, for any particular group.
+     * @return the number of constants in this group
+     */
+    int size();
+
+    /**
+     * Returns the selected constant, resolving it if necessary.
+     * Throws a linkage error if resolution proves impossible.
+     * @param index which constant to select
+     * @return the selected constant
+     * @throws LinkageError if the selected constant needs resolution and cannot be resolved
+     */
+    Object get(int index) throws LinkageError;
+
+    /**
+     * Returns the selected constant,
+     * or the given sentinel value if there is none available.
+     * If the constant cannot be resolved, the sentinel will be returned.
+     * If the constant can (perhaps) be resolved, but has not yet been resolved,
+     * then the sentinel <em>may</em> be returned, at the implementation's discretion.
+     * To force resolution (and a possible exception), call {@link #get(int)}.
+     * @param index the selected constant
+     * @param ifNotPresent the sentinel value to return if the constant is not present
+     * @return the selected constant, if available, else the sentinel value
+     */
+    Object get(int index, Object ifNotPresent);
+
+    /**
+     * Returns an indication of whether a constant may be available.
+     * If it returns {@code true}, it will always return true in the future,
+     * and a call to {@link #get(int)} will never throw an exception.
+     * <p>
+     * After a normal return from {@link #get(int)} or a present
+     * value is reported from {@link #get(int,Object)}, this method
+     * must always return true.
+     * <p>
+     * If this method returns {@code false}, nothing in particular
+     *  can be inferred, since the query only concerns the internal
+     * logic of the {@code ConstantGroup} object which ensures that
+     a successful * query to a constant will always remain successful.
+     * The only way to force a permanent decision about whether
+     * a constant is available is to call {@link #get(int)} and
+     * be ready for an exception if the constant is unavailable.
+     * @param index the selected constant
+     * @return {@code true} if the selected constant is known by
+     *     this object to be present, {@code false} if it is known
+     *     not to be present or
+     */
+    boolean isPresent(int index);
+
+    /// Views
+
+    /**
+     * Create a view on this group as a {@link List} view.
+     * Any request for a constant through this view will
+     * force resolution.
+     * @return a {@code List} view on this group which will force resolution
+     */
+    default List<Object> asList() {
+        return new AbstractConstantGroup.AsList(this, 0, size());
+    }
+
+    /**
+     * Create a view on this group as a {@link List} view.
+     * Any request for a constant through this view will
+     * return the given sentinel value, if the corresponding
+     * call to {@link #get(int,Object)} would do so.
+     * @param ifNotPresent the sentinel value to return if a constant is not present
+     * @return a {@code List} view on this group which will not force resolution
+     */
+    default List<Object> asList(Object ifNotPresent) {
+        return new AbstractConstantGroup.AsList(this, 0, size(), ifNotPresent);
+    }
+
+    /**
+     * Create a view on a sub-sequence of this group.
+     * @param start the index to begin the view
+     * @param end the index to end the view
+     * @return a view on the selected sub-group
+     */
+    default ConstantGroup subGroup(int start, int end) {
+        return new AbstractConstantGroup.SubGroup(this, start, end);
+    }
+
+    /// Bulk operations
+
+    /**
+     * Copy a sequence of constant values into a given buffer.
+     * This is equivalent to {@code end-offset} separate calls to {@code get},
+     * for each index in the range from {@code offset} up to but not including {@code end}.
+     * For the first constant that cannot be resolved,
+     * a {@code LinkageError} is thrown, but only after
+     * preceding constant value have been stored.
+     * @param start index of first constant to retrieve
+     * @param end limiting index of constants to retrieve
+     * @param buf array to receive the requested values
+     * @param pos position in the array to offset storing the values
+     * @return the limiting index, {@code end}
+     * @throws LinkageError if a constant cannot be resolved
+     */
+    default int copyConstants(int start, int end,
+                              Object[] buf, int pos)
+            throws LinkageError
+    {
+        int bufBase = pos - start;  // buf[bufBase + i] = get(i)
+        for (int i = start; i < end; i++) {
+            buf[bufBase + i] = get(i);
+        }
+        return end;
+    }
+
+    /**
+     * Copy a sequence of constant values into a given buffer.
+     * This is equivalent to {@code end-offset} separate calls to {@code get},
+     * for each index in the range from {@code offset} up to but not including {@code end}.
+     * Any constants that cannot be resolved are replaced by the
+     * given sentinel value.
+     * @param start index of first constant to retrieve
+     * @param end limiting index of constants to retrieve
+     * @param buf array to receive the requested values
+     * @param pos position in the array to offset storing the values
+     * @param ifNotPresent sentinel value to store if a value is not available
+     * @return the limiting index, {@code end}
+     * @throws LinkageError if {@code resolve} is true and a constant cannot be resolved
+     */
+    default int copyConstants(int start, int end,
+                              Object[] buf, int pos,
+                              Object ifNotPresent) {
+        int bufBase = pos - start;  // buf[bufBase + i] = get(i)
+        for (int i = start; i < end; i++) {
+            buf[bufBase + i] = get(i, ifNotPresent);
+        }
+        return end;
+    }
+
+    /**
+     * Make a new constant group with the given constants.
+     * The value of {@code ifNotPresent} may be any reference.
+     * If this value is encountered as an element of the
+     * {@code constants} list, the new constant group will
+     * regard that element of the list as logically missing.
+     * If the new constant group is called upon to resolve
+     * a missing element of the group, it will refer to the
+     * given {@code constantProvider}, by calling it on the
+     * index of the missing element.
+     * The {@code constantProvider} must be stable, in the sense
+     * that the outcome of calling it on the same index twice
+     * will produce equivalent results.
+     * If {@code constantProvider} is the null reference, then
+     * it will be treated as if it were a function which raises
+     * {@link NoSuchElementException}.
+     * @param constants the elements of this constant group
+     * @param ifNotPresent sentinel value provided instead of a missing constant
+     * @param constantProvider function to call when a missing constant is resolved
+     * @return a new constant group with the given constants and resolution behavior
+     */
+    static ConstantGroup makeConstantGroup(List<Object> constants,
+                                           Object ifNotPresent,
+                                           IntFunction<Object> constantProvider) {
+        class Impl extends AbstractConstantGroup.WithCache {
+            Impl() {
+                super(constants.size());
+                initializeCache(constants, ifNotPresent);
+            }
+            @Override
+            Object fillCache(int index) {
+                if (constantProvider == null)  super.fillCache(index);
+                return constantProvider.apply(index);
+            }
+        }
+        return new Impl();
+    }
+
+    /**
+     * Make a new constant group with the given constant values.
+     * The constants will be copied from the given list into the
+     * new constant group, forcing resolution if any are missing.
+     * @param constants the constants of this constant group
+     * @return a new constant group with the given constants
+     */
+    static ConstantGroup makeConstantGroup(List<Object> constants) {
+        final Object NP = AbstractConstantGroup.WithCache.NOT_PRESENT;
+        assert(!constants.contains(NP));  // secret value
+        return makeConstantGroup(constants, NP, null);
+    }
+
+}