mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +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
|
@ -28,10 +28,19 @@ package java.lang.invoke;
|
|||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.constant.DirectMethodHandleDesc;
|
||||
import java.lang.constant.MethodHandleDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.lang.invoke.MethodHandleInfo.*;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
|
||||
|
||||
/**
|
||||
* A method handle is a typed, directly executable reference to an underlying method,
|
||||
|
@ -428,7 +437,7 @@ mh.invokeExact(System.out, "Hello, world.");
|
|||
* @author John Rose, JSR 292 EG
|
||||
* @since 1.7
|
||||
*/
|
||||
public abstract class MethodHandle {
|
||||
public abstract class MethodHandle implements Constable {
|
||||
|
||||
/**
|
||||
* Internal marker interface which distinguishes (to the Java compiler)
|
||||
|
@ -1511,6 +1520,60 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
|
|||
return bindArgumentL(0, x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a nominal descriptor for this instance, if one can be
|
||||
* constructed, or an empty {@link Optional} if one cannot be.
|
||||
*
|
||||
* @return An {@link Optional} containing the resulting nominal descriptor,
|
||||
* or an empty {@link Optional} if one cannot be constructed.
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<MethodHandleDesc> describeConstable() {
|
||||
MethodHandleInfo info;
|
||||
ClassDesc owner;
|
||||
String name;
|
||||
MethodTypeDesc type;
|
||||
boolean isInterface;
|
||||
try {
|
||||
info = IMPL_LOOKUP.revealDirect(this);
|
||||
isInterface = info.getDeclaringClass().isInterface();
|
||||
owner = info.getDeclaringClass().describeConstable().orElseThrow();
|
||||
type = info.getMethodType().describeConstable().orElseThrow();
|
||||
name = info.getName();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
switch (info.getReferenceKind()) {
|
||||
case REF_getField:
|
||||
return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.GETTER, owner, name, type.returnType()));
|
||||
case REF_putField:
|
||||
return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.SETTER, owner, name, type.parameterType(0)));
|
||||
case REF_getStatic:
|
||||
return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.STATIC_GETTER, owner, name, type.returnType()));
|
||||
case REF_putStatic:
|
||||
return Optional.of(MethodHandleDesc.ofField(DirectMethodHandleDesc.Kind.STATIC_SETTER, owner, name, type.parameterType(0)));
|
||||
case REF_invokeVirtual:
|
||||
return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.VIRTUAL, owner, name, type));
|
||||
case REF_invokeStatic:
|
||||
return isInterface ?
|
||||
Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, owner, name, type)) :
|
||||
Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, owner, name, type));
|
||||
case REF_invokeSpecial:
|
||||
return isInterface ?
|
||||
Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_SPECIAL, owner, name, type)) :
|
||||
Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.SPECIAL, owner, name, type));
|
||||
case REF_invokeInterface:
|
||||
return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, owner, name, type));
|
||||
case REF_newInvokeSpecial:
|
||||
return Optional.of(MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.CONSTRUCTOR, owner, name, type));
|
||||
default:
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the method handle,
|
||||
* starting with the string {@code "MethodHandle"} and
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 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
|
||||
|
@ -25,21 +25,30 @@
|
|||
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.Wrapper;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.invoke.util.BytecodeDescriptor;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
import sun.invoke.util.VerifyType;
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
|
||||
import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* A method type represents the arguments and return type accepted and
|
||||
|
@ -91,7 +100,10 @@ import sun.invoke.util.VerifyType;
|
|||
* @since 1.7
|
||||
*/
|
||||
public final
|
||||
class MethodType implements java.io.Serializable {
|
||||
class MethodType
|
||||
implements Constable,
|
||||
TypeDescriptor.OfMethod<Class<?>, MethodType>,
|
||||
java.io.Serializable {
|
||||
private static final long serialVersionUID = 292L; // {rtype, {ptype...}}
|
||||
|
||||
// The rtype and ptypes fields define the structural identity of the method type:
|
||||
|
@ -1175,10 +1187,43 @@ class MethodType implements java.io.Serializable {
|
|||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a field type descriptor string for this type
|
||||
*
|
||||
* @return the descriptor string
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public String descriptorString() {
|
||||
return toMethodDescriptorString();
|
||||
}
|
||||
|
||||
/*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
|
||||
return BytecodeDescriptor.unparse(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a nominal descriptor for this instance, if one can be
|
||||
* constructed, or an empty {@link Optional} if one cannot be.
|
||||
*
|
||||
* @return An {@link Optional} containing the resulting nominal descriptor,
|
||||
* or an empty {@link Optional} if one cannot be constructed.
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<MethodTypeDesc> describeConstable() {
|
||||
try {
|
||||
return Optional.of(MethodTypeDesc.of(returnType().describeConstable().orElseThrow(),
|
||||
Stream.of(parameterArray())
|
||||
.map(p -> p.describeConstable().orElseThrow())
|
||||
.toArray(ClassDesc[]::new)));
|
||||
}
|
||||
catch (NoSuchElementException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialization.
|
||||
|
||||
/**
|
||||
|
|
187
src/java.base/share/classes/java/lang/invoke/TypeDescriptor.java
Normal file
187
src/java.base/share/classes/java/lang/invoke/TypeDescriptor.java
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
* 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.invoke;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An entity that has a field or method type descriptor
|
||||
*
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public interface TypeDescriptor {
|
||||
/**
|
||||
* Return the type descriptor string for this instance, which must be either
|
||||
* a field type descriptor (JVMS 4.3.2) or method type descriptor (JVMS 4.3.3).
|
||||
*
|
||||
* @return the type descriptor
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
*/
|
||||
String descriptorString();
|
||||
|
||||
|
||||
/**
|
||||
* An entity that has a field type descriptor
|
||||
*
|
||||
* @param <F> the class implementing {@linkplain TypeDescriptor.OfField}
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @since 12
|
||||
*/
|
||||
interface OfField<F extends TypeDescriptor.OfField<F>> extends TypeDescriptor {
|
||||
/**
|
||||
* Does this field descriptor describe an array type?
|
||||
* @return whether this field descriptor describes an array type
|
||||
*/
|
||||
boolean isArray();
|
||||
|
||||
/**
|
||||
* Does this field descriptor describe a primitive type?
|
||||
* @return whether this field descriptor describes a primitive type
|
||||
*/
|
||||
boolean isPrimitive();
|
||||
|
||||
/**
|
||||
* If this field descriptor describes an array type, return
|
||||
* a descriptor for its component type, otherwise return {@code null}.
|
||||
* @return the component type, or {@code null} if this field descriptor does
|
||||
* not describe an array type
|
||||
*/
|
||||
F componentType();
|
||||
|
||||
/**
|
||||
* Return a descriptor for the array type whose component type is described by this
|
||||
* descriptor
|
||||
* @return the descriptor for the array type
|
||||
*/
|
||||
F arrayType();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An entity that has a method type descriptor
|
||||
*
|
||||
* @param <F> the type representing field type descriptors
|
||||
* @param <M> the class implementing {@linkplain TypeDescriptor.OfMethod}
|
||||
* @jvms 4.3.2 Field Descriptors
|
||||
* @jvms 4.3.3 Method Descriptors
|
||||
* @since 12
|
||||
*/
|
||||
interface OfMethod<F extends TypeDescriptor.OfField<F>, M extends TypeDescriptor.OfMethod<F, M>>
|
||||
extends TypeDescriptor {
|
||||
|
||||
/**
|
||||
* Return the number of parameters in the method type
|
||||
* @return the number of parameters
|
||||
*/
|
||||
int parameterCount();
|
||||
|
||||
/**
|
||||
* Return a field descriptor describing the requested parameter of the method type
|
||||
* described by this descriptor
|
||||
* @param i the index of the parameter
|
||||
* @return a field descriptor for the requested parameter type
|
||||
* @throws IndexOutOfBoundsException if the index is outside the half-open
|
||||
* range {[0, parameterCount)}
|
||||
*/
|
||||
F parameterType(int i);
|
||||
|
||||
/**
|
||||
* Return a field descriptor describing the return type of the method type described
|
||||
* by this descriptor
|
||||
* @return a field descriptor for the return type
|
||||
*/
|
||||
F returnType();
|
||||
|
||||
/**
|
||||
* Return an array of field descriptors for the parameter types of the method type
|
||||
* described by this descriptor
|
||||
* @return field descriptors for the parameter types
|
||||
*/
|
||||
F[] parameterArray();
|
||||
|
||||
/**
|
||||
* Return an immutable list of field descriptors for the parameter types of the method type
|
||||
* described by this descriptor
|
||||
* @return field descriptors for the parameter types
|
||||
*/
|
||||
List<F> parameterList();
|
||||
|
||||
/**
|
||||
* Return a method descriptor that is identical to this one, except that the return
|
||||
* type has been changed to the specified type
|
||||
*
|
||||
* @param newReturn a field descriptor for the new return type
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @return the new method descriptor
|
||||
*/
|
||||
M changeReturnType(F newReturn);
|
||||
|
||||
/**
|
||||
* Return a method descriptor that is identical to this one,
|
||||
* except that a single parameter type has been changed to the specified type.
|
||||
*
|
||||
* @param index the index of the parameter to change
|
||||
* @param paramType a field descriptor describing the new parameter type
|
||||
* @return the new method descriptor
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IndexOutOfBoundsException if the index is outside the half-open
|
||||
* range {[0, parameterCount)}
|
||||
*/
|
||||
M changeParameterType(int index, F paramType);
|
||||
|
||||
/**
|
||||
* Return a method descriptor that is identical to this one,
|
||||
* except that a range of parameter types have been removed.
|
||||
*
|
||||
* @param start the index of the first parameter to remove
|
||||
* @param end the index after the last parameter to remove
|
||||
* @return the new method descriptor
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if {@code start} is outside the half-open
|
||||
* range {@code [0, parameterCount)}, or {@code end} is outside the closed range
|
||||
* {@code [0, parameterCount]}, or if {@code start > end}
|
||||
*/
|
||||
M dropParameterTypes(int start, int end);
|
||||
|
||||
/**
|
||||
* Return a method descriptor that is identical to this one,
|
||||
* except that a range of additional parameter types have been inserted.
|
||||
*
|
||||
* @param pos the index at which to insert the first inserted parameter
|
||||
* @param paramTypes field descriptors describing the new parameter types
|
||||
* to insert
|
||||
* @return the new method descriptor
|
||||
* @throws NullPointerException if any argument is {@code null}
|
||||
* @throws IndexOutOfBoundsException if {@code pos} is outside the closed
|
||||
* range {[0, parameterCount]}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
M insertParameterTypes(int pos, F... paramTypes);
|
||||
}
|
||||
}
|
|
@ -25,19 +25,26 @@
|
|||
|
||||
package java.lang.invoke;
|
||||
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.constant.ConstantDesc;
|
||||
import java.lang.constant.ConstantDescs;
|
||||
import java.lang.constant.DirectMethodHandleDesc;
|
||||
import java.lang.constant.DynamicConstantDesc;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.util.Preconditions;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
|
||||
import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
||||
|
||||
/**
|
||||
* A VarHandle is a dynamically strongly typed reference to a variable, or to a
|
||||
|
@ -437,7 +444,7 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
|||
* @see MethodType
|
||||
* @since 9
|
||||
*/
|
||||
public abstract class VarHandle {
|
||||
public abstract class VarHandle implements Constable {
|
||||
final VarForm vform;
|
||||
|
||||
VarHandle(VarForm vform) {
|
||||
|
@ -1857,6 +1864,32 @@ public abstract class VarHandle {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
VarHandle that = (VarHandle) o;
|
||||
return accessModeType(AccessMode.GET).equals(that.accessModeType(AccessMode.GET)) &&
|
||||
internalEquals(that);
|
||||
}
|
||||
|
||||
abstract boolean internalEquals(VarHandle vh);
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
return 31 * accessModeType(AccessMode.GET).hashCode() + internalHashCode();
|
||||
}
|
||||
|
||||
abstract int internalHashCode();
|
||||
|
||||
@Override
|
||||
public final String toString() {
|
||||
return String.format("VarHandle[varType=%s, coord=%s]",
|
||||
varType().getName(),
|
||||
coordinateTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the variable type of variables referenced by this VarHandle.
|
||||
*
|
||||
|
@ -1951,6 +1984,20 @@ public abstract class VarHandle {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a nominal descriptor for this instance, if one can be
|
||||
* constructed, or an empty {@link Optional} if one cannot be.
|
||||
*
|
||||
* @return An {@link Optional} containing the resulting nominal descriptor,
|
||||
* or an empty {@link Optional} if one cannot be constructed.
|
||||
* @since 12
|
||||
*/
|
||||
@Override
|
||||
public Optional<VarHandleDesc> describeConstable() {
|
||||
// partial function for field and array only
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Stable
|
||||
TypesAndInvokers typesAndInvokers;
|
||||
|
||||
|
@ -2082,4 +2129,163 @@ public abstract class VarHandle {
|
|||
public static void storeStoreFence() {
|
||||
UNSAFE.storeStoreFence();
|
||||
}
|
||||
|
||||
/**
|
||||
* A <a href="package-summary.html#nominal">nominal descriptor</a> for a
|
||||
* {@link VarHandle} constant.
|
||||
*
|
||||
* @since 12
|
||||
*/
|
||||
public static final class VarHandleDesc extends DynamicConstantDesc<VarHandle> {
|
||||
|
||||
/**
|
||||
* Kinds of variable handle descs
|
||||
*/
|
||||
private enum Kind {
|
||||
FIELD(ConstantDescs.BSM_VARHANDLE_FIELD),
|
||||
STATIC_FIELD(ConstantDescs.BSM_VARHANDLE_STATIC_FIELD),
|
||||
ARRAY(ConstantDescs.BSM_VARHANDLE_ARRAY);
|
||||
|
||||
final DirectMethodHandleDesc bootstrapMethod;
|
||||
|
||||
Kind(DirectMethodHandleDesc bootstrapMethod) {
|
||||
this.bootstrapMethod = bootstrapMethod;
|
||||
}
|
||||
|
||||
ConstantDesc[] toBSMArgs(ClassDesc declaringClass, ClassDesc varType) {
|
||||
switch (this) {
|
||||
case FIELD:
|
||||
case STATIC_FIELD:
|
||||
return new ConstantDesc[] {declaringClass, varType };
|
||||
case ARRAY:
|
||||
return new ConstantDesc[] {declaringClass };
|
||||
default:
|
||||
throw new InternalError("Cannot reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final Kind kind;
|
||||
private final ClassDesc declaringClass;
|
||||
private final ClassDesc varType;
|
||||
|
||||
/**
|
||||
* Construct a {@linkplain VarHandleDesc} given a kind, name, and declaring
|
||||
* class.
|
||||
*
|
||||
* @param kind the kind of of the var handle
|
||||
* @param name the unqualified name of the field, for field var handles; otherwise ignored
|
||||
* @param declaringClass a {@link ClassDesc} describing the declaring class,
|
||||
* for field var handles
|
||||
* @param varType a {@link ClassDesc} describing the type of the variable
|
||||
* @throws NullPointerException if any required argument is null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
private VarHandleDesc(Kind kind, String name, ClassDesc declaringClass, ClassDesc varType) {
|
||||
super(kind.bootstrapMethod, name,
|
||||
ConstantDescs.CD_VarHandle,
|
||||
kind.toBSMArgs(declaringClass, varType));
|
||||
this.kind = kind;
|
||||
this.declaringClass = declaringClass;
|
||||
this.varType = varType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
|
||||
* for an instance field.
|
||||
*
|
||||
* @param name the unqualifed name of the field
|
||||
* @param declaringClass a {@link ClassDesc} describing the declaring class,
|
||||
* for field var handles
|
||||
* @param fieldType a {@link ClassDesc} describing the type of the field
|
||||
* @return the {@linkplain VarHandleDesc}
|
||||
* @throws NullPointerException if any of the arguments are null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
public static VarHandleDesc ofField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
|
||||
Objects.requireNonNull(declaringClass);
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(fieldType);
|
||||
return new VarHandleDesc(Kind.FIELD, name, declaringClass, fieldType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
|
||||
* for a static field.
|
||||
*
|
||||
* @param name the unqualified name of the field
|
||||
* @param declaringClass a {@link ClassDesc} describing the declaring class,
|
||||
* for field var handles
|
||||
* @param fieldType a {@link ClassDesc} describing the type of the field
|
||||
* @return the {@linkplain VarHandleDesc}
|
||||
* @throws NullPointerException if any of the arguments are null
|
||||
* @jvms 4.2.2 Unqualified Names
|
||||
*/
|
||||
public static VarHandleDesc ofStaticField(ClassDesc declaringClass, String name, ClassDesc fieldType) {
|
||||
Objects.requireNonNull(declaringClass);
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(fieldType);
|
||||
return new VarHandleDesc(Kind.STATIC_FIELD, name, declaringClass, fieldType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@linkplain VarHandleDesc} corresponding to a {@link VarHandle}
|
||||
* for for an array type.
|
||||
*
|
||||
* @param arrayClass a {@link ClassDesc} describing the type of the array
|
||||
* @return the {@linkplain VarHandleDesc}
|
||||
* @throws NullPointerException if any of the arguments are null
|
||||
*/
|
||||
public static VarHandleDesc ofArray(ClassDesc arrayClass) {
|
||||
Objects.requireNonNull(arrayClass);
|
||||
if (!arrayClass.isArray())
|
||||
throw new IllegalArgumentException("Array class argument not an array: " + arrayClass);
|
||||
return new VarHandleDesc(Kind.ARRAY, ConstantDescs.DEFAULT_NAME, arrayClass, arrayClass.componentType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ClassDesc} describing the type of the variable described
|
||||
* by this descriptor.
|
||||
*
|
||||
* @return the variable type
|
||||
*/
|
||||
public ClassDesc varType() {
|
||||
return varType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VarHandle resolveConstantDesc(MethodHandles.Lookup lookup)
|
||||
throws ReflectiveOperationException {
|
||||
switch (kind) {
|
||||
case FIELD:
|
||||
return lookup.findVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
|
||||
constantName(),
|
||||
(Class<?>) varType.resolveConstantDesc(lookup));
|
||||
case STATIC_FIELD:
|
||||
return lookup.findStaticVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup),
|
||||
constantName(),
|
||||
(Class<?>) varType.resolveConstantDesc(lookup));
|
||||
case ARRAY:
|
||||
return MethodHandles.arrayElementVarHandle((Class<?>) declaringClass.resolveConstantDesc(lookup));
|
||||
default:
|
||||
throw new InternalError("Cannot reach here");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (kind) {
|
||||
case FIELD:
|
||||
case STATIC_FIELD:
|
||||
return String.format("VarHandleDesc[%s%s.%s:%s]",
|
||||
(kind == Kind.STATIC_FIELD) ? "static " : "",
|
||||
declaringClass.displayName(), constantName(), varType.displayName());
|
||||
case ARRAY:
|
||||
return String.format("VarHandleDesc[%s[]]", declaringClass.displayName());
|
||||
default:
|
||||
throw new InternalError("Cannot reach here");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 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
|
||||
|
@ -25,6 +25,9 @@
|
|||
|
||||
package java.lang.invoke;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
|
||||
|
||||
final class VarHandles {
|
||||
|
@ -144,6 +147,38 @@ final class VarHandles {
|
|||
}
|
||||
}
|
||||
|
||||
// Required by instance field handles
|
||||
static Field getFieldFromReceiverAndOffset(Class<?> receiverType,
|
||||
long offset,
|
||||
Class<?> fieldType) {
|
||||
for (Field f : receiverType.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(f.getModifiers())) continue;
|
||||
|
||||
if (offset == UNSAFE.objectFieldOffset(f)) {
|
||||
assert f.getType() == fieldType;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
throw new InternalError("Field not found at offset");
|
||||
}
|
||||
|
||||
// Required by instance static field handles
|
||||
static Field getStaticFieldFromBaseAndOffset(Object base,
|
||||
long offset,
|
||||
Class<?> fieldType) {
|
||||
// @@@ This is a little fragile assuming the base is the class
|
||||
Class<?> receiverType = (Class<?>) base;
|
||||
for (Field f : receiverType.getDeclaredFields()) {
|
||||
if (!Modifier.isStatic(f.getModifiers())) continue;
|
||||
|
||||
if (offset == UNSAFE.staticFieldOffset(f)) {
|
||||
assert f.getType() == fieldType;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
throw new InternalError("Static field not found at offset");
|
||||
}
|
||||
|
||||
static VarHandle makeArrayElementHandle(Class<?> arrayClass) {
|
||||
if (!arrayClass.isArray())
|
||||
throw new IllegalArgumentException("not an array: " + arrayClass);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
|
@ -27,7 +27,9 @@ package java.lang.invoke;
|
|||
import jdk.internal.util.Preconditions;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
|
||||
import java.lang.invoke.VarHandle.VarHandleDesc;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
|
||||
|
||||
|
@ -61,6 +63,30 @@ final class VarHandle$Type$s {
|
|||
return accessMode.at.accessModeType(receiverType, {#if[Object]?fieldType:$type$.class});
|
||||
}
|
||||
|
||||
@Override
|
||||
final boolean internalEquals(VarHandle vh) {
|
||||
FieldInstanceReadOnly that = (FieldInstanceReadOnly) vh;
|
||||
return fieldOffset == that.fieldOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
final int internalHashCode() {
|
||||
return Long.hashCode(fieldOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VarHandleDesc> describeConstable() {
|
||||
var receiverTypeRef = receiverType.describeConstable();
|
||||
var fieldTypeRef = {#if[Object]?fieldType:$type$.class}.describeConstable();
|
||||
if (!receiverTypeRef.isPresent() || !fieldTypeRef.isPresent())
|
||||
return Optional.empty();
|
||||
|
||||
// Reflect on this VarHandle to extract the field name
|
||||
String name = VarHandles.getFieldFromReceiverAndOffset(
|
||||
receiverType, fieldOffset, {#if[Object]?fieldType:$type$.class}).getName();
|
||||
return Optional.of(VarHandleDesc.ofField(receiverTypeRef.get(), name, fieldTypeRef.get()));
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
static $type$ get(FieldInstanceReadOnly handle, Object holder) {
|
||||
return UNSAFE.get$Type$(Objects.requireNonNull(handle.receiverType.cast(holder)),
|
||||
|
@ -323,6 +349,32 @@ final class VarHandle$Type$s {
|
|||
#end[Object]
|
||||
}
|
||||
|
||||
@Override
|
||||
final boolean internalEquals(VarHandle vh) {
|
||||
FieldStaticReadOnly that = (FieldStaticReadOnly) vh;
|
||||
return base == that.base && fieldOffset == that.fieldOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
final int internalHashCode() {
|
||||
return 31 * Long.hashCode(fieldOffset) + base.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VarHandleDesc> describeConstable() {
|
||||
var fieldTypeRef = {#if[Object]?fieldType:$type$.class}.describeConstable();
|
||||
if (!fieldTypeRef.isPresent())
|
||||
return Optional.empty();
|
||||
|
||||
// Reflect on this VarHandle to extract the field name
|
||||
var staticField = VarHandles.getStaticFieldFromBaseAndOffset(
|
||||
base, fieldOffset, {#if[Object]?fieldType:$type$.class});
|
||||
var receiverTypeRef = staticField.getDeclaringClass().describeConstable();
|
||||
if (!receiverTypeRef.isPresent())
|
||||
return Optional.empty();
|
||||
return Optional.of(VarHandleDesc.ofStaticField(receiverTypeRef.get(), staticField.getName(), fieldTypeRef.get()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final MethodType accessModeTypeUncached(AccessMode accessMode) {
|
||||
return accessMode.at.accessModeType(null, {#if[Object]?fieldType:$type$.class});
|
||||
|
@ -587,6 +639,29 @@ final class VarHandle$Type$s {
|
|||
#end[Object]
|
||||
}
|
||||
|
||||
@Override
|
||||
final boolean internalEquals(VarHandle vh) {
|
||||
// Equality of access mode types of AccessMode.GET is sufficient for
|
||||
// equality checks
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
final int internalHashCode() {
|
||||
// The hash code of the access mode types of AccessMode.GET is
|
||||
// sufficient for hash code generation
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VarHandleDesc> describeConstable() {
|
||||
var arrayTypeRef = {#if[Object]?arrayType:$type$[].class}.describeConstable();
|
||||
if (!arrayTypeRef.isPresent())
|
||||
return Optional.empty();
|
||||
|
||||
return Optional.of(VarHandleDesc.ofArray(arrayTypeRef.get()));
|
||||
}
|
||||
|
||||
@Override
|
||||
final MethodType accessModeTypeUncached(AccessMode accessMode) {
|
||||
return accessMode.at.accessModeType({#if[Object]?arrayType:$type$[].class}, {#if[Object]?arrayType.getComponentType():$type$.class}, int.class);
|
||||
|
|
|
@ -67,6 +67,17 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
|
|||
super(form);
|
||||
this.be = be;
|
||||
}
|
||||
|
||||
@Override
|
||||
final boolean internalEquals(VarHandle vh) {
|
||||
ByteArrayViewVarHandle that = (ByteArrayViewVarHandle) vh;
|
||||
return be == that.be;
|
||||
}
|
||||
|
||||
@Override
|
||||
final int internalHashCode() {
|
||||
return Boolean.hashCode(be);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ArrayHandle extends ByteArrayViewVarHandle {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue