8296958: [JVMCI] add API for retrieving ConstantValue attributes

Reviewed-by: never
This commit is contained in:
Doug Simon 2022-11-16 19:56:14 +00:00
parent 8c26d029b5
commit 4ce4f384d7
9 changed files with 199 additions and 6 deletions
src
test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test

@ -576,6 +576,16 @@ C2V_VMENTRY_NULL(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror))
return JVMCIENV->get_jobject(result);
C2V_END
C2V_VMENTRY_NULL(jobject, getUncachedStringInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index))
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
constantTag tag = cp->tag_at(index);
if (!tag.is_string()) {
JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Unexpected constant pool tag at index %d: %d", index, tag.value()));
}
oop obj = cp->uncached_string_at(index, CHECK_NULL);
return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(obj));
C2V_END
C2V_VMENTRY_NULL(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index))
constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
oop obj = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
@ -2834,6 +2844,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "lookupMethodInPool", CC "(" HS_CONSTANT_POOL2 "IB" HS_METHOD2 ")" HS_METHOD, FN_PTR(lookupMethodInPool)},
{CC "constantPoolRemapInstructionOperandFromCache", CC "(" HS_CONSTANT_POOL2 "I)I", FN_PTR(constantPoolRemapInstructionOperandFromCache)},
{CC "resolveBootstrapMethod", CC "(" HS_CONSTANT_POOL2 "I)[" OBJECT, FN_PTR(resolveBootstrapMethod)},
{CC "getUncachedStringInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(getUncachedStringInPool)},
{CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT, FN_PTR(resolvePossiblyCachedConstantInPool)},
{CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL2 "I)" HS_KLASS, FN_PTR(resolveTypeInPool)},
{CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL2 "I" HS_METHOD2 "B[I)" HS_KLASS, FN_PTR(resolveFieldInPool)},

@ -174,6 +174,7 @@
\
nonstatic_field(JavaThread, _threadObj, OopHandle) \
nonstatic_field(JavaThread, _vthread, OopHandle) \
nonstatic_field(JavaThread, _extentLocalCache, OopHandle) \
nonstatic_field(JavaThread, _anchor, JavaFrameAnchor) \
nonstatic_field(JavaThread, _vm_result, oop) \
nonstatic_field(JavaThread, _stack_overflow_state._stack_overflow_limit, address) \

@ -251,6 +251,18 @@ final class CompilerToVM {
native HotSpotResolvedJavaType lookupClass(Class<?> javaClass);
/**
* Resolves the entry at index {@code cpi} in {@code constantPool} to an interned String object.
*
* The behavior of this method is undefined if {@code cpi} does not denote an
* {@code JVM_CONSTANT_String}.
*/
JavaConstant getUncachedStringInPool(HotSpotConstantPool constantPool, int cpi) {
return getUncachedStringInPool(constantPool, constantPool.getConstantPoolPointer(), cpi);
}
private native JavaConstant getUncachedStringInPool(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi);
/**
* Resolves the entry at index {@code cpi} in {@code constantPool} to an object, looking in the
* constant pool cache first.

@ -619,6 +619,27 @@ public final class HotSpotConstantPool implements ConstantPool, MetaspaceHandleO
}
}
/**
* Gets the {@link JavaConstant} for the {@code ConstantValue} attribute of a field.
*/
JavaConstant getStaticFieldConstantValue(int cpi) {
final JvmConstant tag = getTagAt(cpi);
switch (tag.name) {
case "Integer":
return JavaConstant.forInt(getIntAt(cpi));
case "Long":
return JavaConstant.forLong(getLongAt(cpi));
case "Float":
return JavaConstant.forFloat(getFloatAt(cpi));
case "Double":
return JavaConstant.forDouble(getDoubleAt(cpi));
case "String":
return compilerToVM().getUncachedStringInPool(this, cpi);
default:
throw new IllegalArgumentException("Illegal entry for a ConstantValue attribute:" + tag);
}
}
@Override
public Object lookupConstant(int cpi) {
assert cpi != 0;

@ -214,4 +214,9 @@ class HotSpotResolvedJavaFieldImpl implements HotSpotResolvedJavaField {
}
return runtime().reflection.getFieldAnnotation(this, annotationClass);
}
@Override
public JavaConstant getConstantValue() {
return holder.createFieldInfo(index).getConstantValue();
}
}

@ -689,6 +689,10 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
return readFieldSlot(config().fieldInfoSignatureIndexOffset);
}
private int getConstantValueIndex() {
return readFieldSlot(config().fieldInfoConstantValueIndexOffset);
}
public int getOffset() {
HotSpotVMConfig config = config();
final int lowPacked = readFieldSlot(config.fieldInfoLowPackedOffset);
@ -724,6 +728,19 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
return isInternal() ? config().symbolAt(signatureIndex) : getConstantPool().lookupUtf8(signatureIndex);
}
/**
* Gets the {@link JavaConstant} for the {@code ConstantValue} attribute of this field.
*
* @return {@code null} if this field has no {@code ConstantValue} attribute
*/
public JavaConstant getConstantValue() {
int cvIndex = getConstantValueIndex();
if (cvIndex == 0) {
return null;
}
return constantPool.getStaticFieldConstantValue(cvIndex);
}
public JavaType getType() {
String signature = getSignature();
return runtime().lookupType(signature, HotSpotResolvedObjectTypeImpl.this, false);

@ -119,6 +119,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess {
final int fieldInfoAccessFlagsOffset = getConstant("FieldInfo::access_flags_offset", Integer.class);
final int fieldInfoNameIndexOffset = getConstant("FieldInfo::name_index_offset", Integer.class);
final int fieldInfoSignatureIndexOffset = getConstant("FieldInfo::signature_index_offset", Integer.class);
final int fieldInfoConstantValueIndexOffset = getConstant("FieldInfo::initval_index_offset", Integer.class);
final int fieldInfoLowPackedOffset = getConstant("FieldInfo::low_packed_offset", Integer.class);
final int fieldInfoHighPackedOffset = getConstant("FieldInfo::high_packed_offset", Integer.class);
final int fieldInfoFieldSlots = getConstant("FieldInfo::field_slots", Integer.class);

@ -63,4 +63,15 @@ public interface ResolvedJavaField extends JavaField, ModifiersProvider, Annotat
*/
@Override
ResolvedJavaType getDeclaringClass();
/**
* Gets the value of the {@code ConstantValue} attribute ({@jvms 4.7.2}) associated with this
* field.
*
* @return {@code null} if this field has no {@code ConstantValue} attribute
* @throws UnsupportedOperationException if this operation is not supported
*/
default JavaConstant getConstantValue() {
throw new UnsupportedOperationException();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2022, 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,9 +25,9 @@
* @test
* @requires vm.jvmci
* @library ../../../../../
* @ignore 8249621
* @modules jdk.internal.vm.ci/jdk.vm.ci.meta
* jdk.internal.vm.ci/jdk.vm.ci.runtime
* jdk.internal.vm.ci/jdk.vm.ci.common
* java.base/jdk.internal.misc
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaField
*/
@ -37,6 +37,8 @@ package jdk.vm.ci.runtime.test;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
@ -46,6 +48,7 @@ import java.io.PrintStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
@ -54,6 +57,9 @@ import java.util.Set;
import org.junit.Assert;
import org.junit.Test;
import jdk.vm.ci.common.JVMCIError;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
@ -117,6 +123,54 @@ public class TestResolvedJavaField extends FieldUniverse {
}
}
@Test
public void getDeclaringClassTest() {
for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
ResolvedJavaField field = e.getValue();
ResolvedJavaType actual = field.getDeclaringClass();
ResolvedJavaType expect = metaAccess.lookupJavaType(e.getKey().getDeclaringClass());
assertEquals(field.toString(), expect, actual);
}
}
@Test
public void getOffsetTest() {
for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
Field javaField = e.getKey();
ResolvedJavaField field = e.getValue();
int actual = field.getOffset();
long expect = field.isStatic() ? unsafe.staticFieldOffset(javaField) : unsafe.objectFieldOffset(javaField);
assertEquals(field.toString(), expect, actual);
}
}
@Test
public void isFinalTest() {
for (Map.Entry<Field, ResolvedJavaField> e : fields.entrySet()) {
ResolvedJavaField field = e.getValue();
boolean actual = field.isFinal();
boolean expect = Modifier.isFinal(e.getKey().getModifiers());
assertEquals(field.toString(), expect, actual);
}
}
@Test
public void isInternalTest() {
for (Class<?> c : classes) {
ResolvedJavaType type = metaAccess.lookupJavaType(c);
for (ResolvedJavaField field : type.getInstanceFields(false)) {
if (field.isInternal()) {
try {
c.getDeclaredField(field.getName());
throw new AssertionError("got reflection object for internal field: " + field);
} catch (NoSuchFieldException e) {
// expected
}
}
}
}
}
private Method findTestMethod(Method apiMethod) {
String testName = apiMethod.getName() + "Test";
for (Method m : getClass().getDeclaredMethods()) {
@ -129,10 +183,6 @@ public class TestResolvedJavaField extends FieldUniverse {
// @formatter:off
private static final String[] untestedApiMethods = {
"getDeclaringClass",
"getOffset",
"isInternal",
"isFinal"
};
// @formatter:on
@ -232,6 +282,70 @@ public class TestResolvedJavaField extends FieldUniverse {
field.getAnnotations();
}
}
@Test
public void getConstantValueTest() {
ConstantReflectionProvider cr = constantReflection;
Map<String, JavaConstant> expects = Map.of(
"INT", JavaConstant.forInt(42),
"SHORT", JavaConstant.forInt(43),
"CHAR", JavaConstant.forInt(44),
"BYTE", JavaConstant.forInt(45),
"FLOAT", JavaConstant.forFloat(46.46F),
"LONG", JavaConstant.forLong(47L),
"DOUBLE", JavaConstant.forDouble(48.48D));
ResolvedJavaType type = metaAccess.lookupJavaType(FieldsWithConstantValueAttributes.class);
for (ResolvedJavaField field : type.getStaticFields()) {
JavaConstant actual = field.getConstantValue();
String name = field.getName();
if (name.endsWith("2")) {
assertNull(field.toString(), actual);
} else if (name.equals("STRING")) {
JavaConstant expect = cr.forString("STRING_VALUE");
assertEquals(field.toString(), expect, actual);
// String ConstantValues are interned so should not
// be identical to a newly allocated String
expect = cr.forString(new String("STRING_VALUE"));
assertNotEquals(field.toString(), expect, actual);
} else {
JavaConstant expect = expects.get(name);
assertEquals(field.toString(), expect, actual);
}
}
}
}
class FieldsWithConstantValueAttributes {
public static final String STRING = "STRING_VALUE";
public static final int INT = 42;
public static final short SHORT = 43;
public static final char CHAR = 44;
public static final byte BYTE = 45;
public static final float FLOAT = 46.46F;
public static final long LONG = 47L;
public static final double DOUBLE = 48.48D;
public static final String STRING2;
public static final int INT2;
public static final short SHORT2;
public static final char CHAR2;
public static final byte BYTE2;
public static final float FLOAT2;
public static final long LONG2;
public static final double DOUBLE2;
static {
JVMCIError.shouldNotReachHere("should not be initialized");
STRING2 = STRING;
INT2 = INT;
SHORT2 = SHORT;
BYTE2 = BYTE;
CHAR2 = CHAR;
FLOAT2 = FLOAT;
LONG2 = LONG;
DOUBLE2 = DOUBLE;
}
}
class TypeWithUnresolvedFieldType {