| /* | |
| * Copyright (c) 2017, 2024, 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); | |
| } | |
| } |