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:
Vicente Romero 2018-12-09 12:36:24 -05:00
parent b80d335354
commit 9846588b31
72 changed files with 6719 additions and 103 deletions

View file

@ -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

View file

@ -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.
/**

View 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);
}
}

View file

@ -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");
}
}
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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 {