8296958: [JVMCI] add API for retrieving ConstantValue attributes
Reviewed-by: never
This commit is contained in:
parent
8c26d029b5
commit
4ce4f384d7
src
hotspot/share/jvmci
jdk.internal.vm.ci/share/classes
jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot
CompilerToVM.javaHotSpotConstantPool.javaHotSpotResolvedJavaFieldImpl.javaHotSpotResolvedObjectTypeImpl.javaHotSpotVMConfig.java
jdk.vm.ci.meta/src/jdk/vm/ci/meta
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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user