mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8210031: implementation for JVM Constants API
Co-authored-by: Brian Goetz <brian.goetz@oracle.com> Reviewed-by: jrose, mcimadamore, darcy, mchung, rriggs, dholmes, forax
This commit is contained in:
parent
b80d335354
commit
9846588b31
72 changed files with 6719 additions and 103 deletions
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 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.constant;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandleInfo;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_getField;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_getStatic;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_invokeInterface;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_invokeSpecial;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_invokeStatic;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_invokeVirtual;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_newInvokeSpecial;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_putField;
|
||||
import static java.lang.invoke.MethodHandleInfo.REF_putStatic;
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a direct
|
||||
* {@link MethodHandle}. A {@linkplain DirectMethodHandleDesc} corresponds to
|
||||
* a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile.
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@linkplain DirectMethodHandleDesc}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except
|
||||
* by explicitly permitted types. Non-platform classes should not implement
|
||||
* {@linkplain DirectMethodHandleDesc} directly.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public interface DirectMethodHandleDesc extends MethodHandleDesc {
|
||||
/**
|
||||
* Kinds of method handles that can be described with {@linkplain DirectMethodHandleDesc}.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
enum Kind {
|
||||
/** A method handle for a method invoked as with {@code invokestatic} */
|
||||
STATIC(REF_invokeStatic),
|
||||
/** A method handle for a method invoked as with {@code invokestatic} */
|
||||
INTERFACE_STATIC(REF_invokeStatic, true),
|
||||
/** A method handle for a method invoked as with {@code invokevirtual} */
|
||||
VIRTUAL(REF_invokeVirtual),
|
||||
/** A method handle for a method invoked as with {@code invokeinterface} */
|
||||
INTERFACE_VIRTUAL(REF_invokeInterface, true),
|
||||
/** A method handle for a method invoked as with {@code invokespecial} */
|
||||
SPECIAL(REF_invokeSpecial),
|
||||
/** A method handle for an interface method invoked as with {@code invokespecial} */
|
||||
INTERFACE_SPECIAL(REF_invokeSpecial, true),
|
||||
/** A method handle for a constructor */
|
||||
CONSTRUCTOR(REF_newInvokeSpecial),
|
||||
/** A method handle for a read accessor for an instance field */
|
||||
GETTER(REF_getField),
|
||||
/** A method handle for a write accessor for an instance field */
|
||||
SETTER(REF_putField),
|
||||
/** A method handle for a read accessor for a static field */
|
||||
STATIC_GETTER(REF_getStatic),
|
||||
/** A method handle for a write accessor for a static field */
|
||||
STATIC_SETTER(REF_putStatic);
|
||||
|
||||
/** The corresponding {@code refKind} value for this kind of method handle,
|
||||
* as defined by {@link MethodHandleInfo}
|
||||
*/
|
||||
public final int refKind;
|
||||
|
||||
/** Is this an interface
|
||||
*/
|
||||
public final boolean isInterface;
|
||||
Kind(int refKind) {
|
||||
this(refKind, false);
|
||||
}
|
||||
|
||||
Kind(int refKind, boolean isInterface) { this.refKind = refKind; this.isInterface = isInterface; }
|
||||
|
||||
/**
|
||||
* Returns the enumeration member with the given {@code refKind} field.
|
||||
* Behaves as if {@code valueOf(refKind, false)}. As a special case,
|
||||
* if {@code refKind} is {@code REF_invokeInterface} (9) then the
|
||||
* {@code isInterface} field will be true.
|
||||
*
|
||||
* @param refKind refKind of desired member
|
||||
* @return the matching enumeration member
|
||||
* @throws IllegalArgumentException if there is no such member
|
||||
*/
|
||||
public static Kind valueOf(int refKind) {
|
||||
return valueOf(refKind, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enumeration member with the given the {@code refKind} and
|
||||
* {@code isInterface} arguments.
|
||||
* For most values of {@code refKind} there is an exact match regardless of the value of {@code isInterface}.
|
||||
* These are:
|
||||
* <UL>
|
||||
* <LI>{@code REF_invokeVirtual} which matches to {@code VIRTUAL}
|
||||
* <LI>{@code REF_invokeInterface} which matches to {@code INTERFACE_VIRTUAL}
|
||||
* <LI>{@code REF_newInvokeSpecial} which matches to {@code CONSTRUCTOR}
|
||||
* <LI>{@code REF_getField} which matches to {@code GETTER}
|
||||
* <LI>{@code REF_putField} which matches to {@code SETTER}
|
||||
* <LI>{@code REF_getStatic} which matches to {@code STATIC_GETTER}
|
||||
* <LI>{@code REF_putStatic} which matches to {@code STATIC_SETTER}
|
||||
* </UL>
|
||||
* As for the rest, the returned kind will depend on the value (false or true accordingly) of {@code isInterface}:
|
||||
* <UL>
|
||||
* <LI>{@code REF_invokeStatic} which matches to {@code STATIC} or {@code INTERFACE_STATIC}
|
||||
* <LI>{@code REF_invokeSpecial} which matches to {@code SPECIAL} or {@code INTERFACE_SPECIAL}
|
||||
* </UL>
|
||||
* @param refKind refKind of desired member
|
||||
* @param isInterface whether desired member is for interface methods
|
||||
* @return the matching enumeration member
|
||||
* @throws IllegalArgumentException if there is no such member
|
||||
*/
|
||||
public static Kind valueOf(int refKind, boolean isInterface) {
|
||||
int i = tableIndex(refKind, isInterface);
|
||||
if (i >= 0 && i < TABLE.length) {
|
||||
Kind kind = TABLE[i];
|
||||
if (kind == null) {
|
||||
throw new IllegalArgumentException(String.format("refKind=%d", refKind));
|
||||
}
|
||||
if (kind.refKind == refKind && kind.isInterface == isInterface) {
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(String.format("refKind=%d", refKind));
|
||||
}
|
||||
|
||||
private static int tableIndex(int refKind, boolean isInterface) {
|
||||
if (refKind < 0) return refKind;
|
||||
return (refKind * 2) + (isInterface ? 1 : 0);
|
||||
}
|
||||
|
||||
private static final @Stable Kind[] TABLE;
|
||||
|
||||
static {
|
||||
// Pack the static table.
|
||||
int max = 0;
|
||||
for (Kind k : values())
|
||||
max = Math.max(max, tableIndex(k.refKind, true));
|
||||
|
||||
TABLE = new Kind[max+1];
|
||||
for (Kind kind : values()) {
|
||||
int i = tableIndex(kind.refKind, kind.isInterface);
|
||||
if (i >= TABLE.length || TABLE[i] != null)
|
||||
throw new AssertionError("TABLE entry for " + kind);
|
||||
TABLE[i] = kind;
|
||||
}
|
||||
|
||||
// Pack in some aliases also.
|
||||
int ii = tableIndex(REF_invokeInterface, false);
|
||||
if (TABLE[ii] != null)
|
||||
throw new AssertionError("TABLE entry for (invokeInterface, false) used by " + TABLE[ii]);
|
||||
TABLE[ii] = INTERFACE_VIRTUAL;
|
||||
|
||||
for (Kind kind : values()) {
|
||||
if (!kind.isInterface) {
|
||||
// Add extra cache entry to alias the isInterface case.
|
||||
// For example, (REF_getStatic, X) will produce STATIC_GETTER
|
||||
// for either truth value of X.
|
||||
int i = tableIndex(kind.refKind, true);
|
||||
if (TABLE[i] == null) {
|
||||
// There is not a specific Kind for interfaces
|
||||
if (kind == VIRTUAL) kind = INTERFACE_VIRTUAL;
|
||||
if (TABLE[i] == null) TABLE[i] = kind;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this {@code Kind} correspond to a virtual method invocation?
|
||||
*
|
||||
* @return if this {@code Kind} corresponds to a virtual method invocation
|
||||
*/
|
||||
boolean isVirtualMethod() {
|
||||
switch (this) {
|
||||
case VIRTUAL:
|
||||
case SPECIAL:
|
||||
case INTERFACE_VIRTUAL:
|
||||
case INTERFACE_SPECIAL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code kind} of the method handle described by this nominal
|
||||
* descriptor.
|
||||
*
|
||||
* @return the {@link Kind}
|
||||
*/
|
||||
Kind kind();
|
||||
|
||||
/**
|
||||
* Returns the {@code refKind} of the method handle described by this nominal
|
||||
* reference, as defined by {@link MethodHandleInfo}.
|
||||
*
|
||||
* @return the reference kind
|
||||
*/
|
||||
int refKind();
|
||||
|
||||
/**
|
||||
* Indicates if the method is declared by an interface
|
||||
*
|
||||
* @return true if the method is declared by an interface
|
||||
*/
|
||||
boolean isOwnerInterface();
|
||||
|
||||
/**
|
||||
* Returns a {@link ClassDesc} describing the class declaring the
|
||||
* method or field described by this nominal descriptor.
|
||||
*
|
||||
* @return the class declaring the method or field
|
||||
*/
|
||||
ClassDesc owner();
|
||||
|
||||
/**
|
||||
* Returns the name of the method or field described by this nominal descriptor.
|
||||
* For constructors, returns the reserved name {@code "<init>"}.
|
||||
*
|
||||
* @return the name of the method or field
|
||||
*/
|
||||
String methodName();
|
||||
|
||||
/**
|
||||
* Returns the lookup descriptor of the method handle described by this descriptor,
|
||||
* after adjusting for the invocation mode. This will correspond to either
|
||||
* a method type descriptor string (for methods and constructors), or a field
|
||||
* descriptor string (for field access method handles). The lookup descriptor
|
||||
* string is in the same format as accepted by {@link MethodHandleDesc#of(Kind, ClassDesc, String, String)}.
|
||||
*
|
||||
* @return the lookup descriptor string
|
||||
*/
|
||||
String lookupDescriptor();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue