blob: 7755b1dfe6a7d7ab75eba92ca4d3f55999c4b9e6 [file] [log] [blame]
/*
* 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);
}
}