288 lines
12 KiB
Java
288 lines
12 KiB
Java
/*
|
|
* Copyright (c) 2017, 2020, 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);
|
|
}
|
|
|
|
}
|