Skip to content

Commit a7b97f3

Browse files
Crema: Implement Executable parameter reflection
1 parent 8f20e09 commit a7b97f3

8 files changed

Lines changed: 81 additions & 34 deletions

File tree

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeReflectionMetadata.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,7 @@ private Method fromResolvedMethod(DynamicHub declaringClass, CremaResolvedJavaMe
130130
resolvedJavaMethod.getRawParameterAnnotations(),
131131
resolvedJavaMethod.getRawAnnotationDefault(),
132132
resolvedJavaMethod.getAccessor(receiverType, parameterTypes),
133-
/* (GR-74007) resolvedJavaMethod.getRawParameters() */
134-
null,
133+
resolvedJavaMethod.getParametersAttribute(),
135134
resolvedJavaMethod.getRawTypeAnnotations(),
136135
declaringClass.getLayerId());
137136
}
@@ -162,8 +161,7 @@ private Constructor<?> fromResolvedConstructor(DynamicHub declaringClass, CremaR
162161
resolvedConstructor.getRawAnnotations(),
163162
resolvedConstructor.getRawParameterAnnotations(),
164163
resolvedConstructor.getAccessor(DynamicHub.toClass(declaringClass), parameterTypes),
165-
/* (GR-74007) resolvedConstructor.getRawParameters() */
166-
new byte[0],
164+
resolvedConstructor.getParametersAttribute(),
167165
resolvedConstructor.getRawTypeAnnotations());
168166
}
169167

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/crema/CremaResolvedJavaMethod.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
package com.oracle.svm.core.hub.crema;
2626

27+
import com.oracle.svm.espresso.classfile.attributes.MethodParametersAttribute;
28+
2729
import jdk.vm.ci.meta.JavaType;
2830
import jdk.vm.ci.meta.ResolvedJavaMethod;
2931

@@ -37,35 +39,36 @@ public interface CremaResolvedJavaMethod extends ResolvedJavaMethod {
3739
JavaType[] getDeclaredExceptions();
3840

3941
/**
40-
* Retrieves the raw annotation bytes for this field.
42+
* Retrieves the raw annotation bytes for this method.
4143
*
4244
* @return the raw annotations as a byte array
4345
*/
4446
byte[] getRawAnnotations();
4547

4648
/**
47-
* Retrieves the raw parameter annotation bytes for this field.
49+
* Retrieves the raw parameter annotation bytes for this method.
4850
*
49-
* @return the raw paramater annotations as a byte array
51+
* @return the raw parameter annotations as a byte array
5052
*/
5153
byte[] getRawParameterAnnotations();
5254

5355
/**
54-
* Retrieves the raw annotation default bytes for this field.
56+
* Retrieves the raw annotation default bytes for this method.
5557
*
56-
* @return the raw annotations default as a byte array
58+
* @return the raw annotation default as a byte array
5759
*/
5860
byte[] getRawAnnotationDefault();
5961

6062
/**
61-
* Retrieves the raw parameter bytes for this field.
63+
* Retrieves the {@code MethodParameters} attribute for this method.
6264
*
63-
* @return the raw parameters as a byte array
65+
* @return the {@code MethodParameters} attribute, or {@code null} if the attribute is not
66+
* present
6467
*/
65-
byte[] getRawParameters();
68+
MethodParametersAttribute getParametersAttribute();
6669

6770
/**
68-
* Retrieves the raw type annotation bytes for this field.
71+
* Retrieves the raw type annotation bytes for this method.
6972
*
7073
* @return the raw type annotations as a byte array
7174
*/

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/crema/CremaSupport.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@
3333
import com.oracle.svm.core.hub.RuntimeClassLoading.ClassDefinitionInfo;
3434
import com.oracle.svm.core.hub.registry.SymbolsSupport;
3535
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
36+
import com.oracle.svm.espresso.classfile.ConstantPool;
3637
import com.oracle.svm.espresso.classfile.ParserKlass;
3738
import com.oracle.svm.espresso.classfile.descriptors.ByteSequence;
3839
import com.oracle.svm.espresso.classfile.descriptors.Signature;
3940
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
4041
import com.oracle.svm.espresso.classfile.descriptors.Type;
4142
import com.oracle.svm.espresso.shared.resolver.CallKind;
4243

43-
import jdk.vm.ci.meta.ConstantPool;
4444
import jdk.vm.ci.meta.ResolvedJavaField;
4545
import jdk.vm.ci.meta.ResolvedJavaMethod;
4646
import jdk.vm.ci.meta.ResolvedJavaType;
@@ -158,5 +158,5 @@ static CremaSupport singleton() {
158158
@Platforms(Platform.HOSTED_ONLY.class)
159159
void setEnterDirectInterpreterStubEntryPoint(CFunctionPointer stubEntryPoint);
160160

161-
ConstantPool getConstantPool(DynamicHub hub);
161+
<T extends ConstantPool & jdk.vm.ci.meta.ConstantPool> T getConstantPool(DynamicHub hub);
162162
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/ReflectionObjectFactory.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ public static Field newField(RuntimeDynamicAccessMetadata dynamicAccessMetadata,
5252

5353
public static Method newMethod(RuntimeDynamicAccessMetadata dynamicAccessMetadata, Class<?> declaringClass, String name, Class<?>[] parameterTypes, Class<?> returnType, Class<?>[] exceptionTypes,
5454
int modifiers,
55-
String signature, byte[] annotations, byte[] parameterAnnotations, byte[] annotationDefault, Object accessor, byte[] rawParameters,
55+
String signature, byte[] annotations, byte[] parameterAnnotations, byte[] annotationDefault, Object accessor, Object parameterMetadata,
5656
byte[] typeAnnotations, int layerId) {
5757
Target_java_lang_reflect_Method method = new Target_java_lang_reflect_Method();
5858
method.constructor(declaringClass, name, parameterTypes, returnType, exceptionTypes, modifiers, -1, signature, annotations, parameterAnnotations, annotationDefault);
5959
method.methodAccessorFromMetadata = (Target_jdk_internal_reflect_MethodAccessor) accessor;
60-
SubstrateUtil.cast(method, Target_java_lang_reflect_Executable.class).rawParameters = rawParameters;
60+
SubstrateUtil.cast(method, Target_java_lang_reflect_Executable.class).parameterMetadata = parameterMetadata;
6161
Target_java_lang_reflect_AccessibleObject accessibleObject = SubstrateUtil.cast(method, Target_java_lang_reflect_AccessibleObject.class);
6262
accessibleObject.typeAnnotations = typeAnnotations;
6363
accessibleObject.dynamicAccessMetadata = dynamicAccessMetadata;
@@ -67,11 +67,11 @@ public static Method newMethod(RuntimeDynamicAccessMetadata dynamicAccessMetadat
6767

6868
public static Constructor<?> newConstructor(RuntimeDynamicAccessMetadata dynamicAccessMetadata, Class<?> declaringClass, Class<?>[] parameterTypes, Class<?>[] exceptionTypes, int modifiers,
6969
String signature,
70-
byte[] annotations, byte[] parameterAnnotations, Object accessor, byte[] rawParameters, byte[] typeAnnotations) {
70+
byte[] annotations, byte[] parameterAnnotations, Object accessor, Object parameterMetadata, byte[] typeAnnotations) {
7171
Target_java_lang_reflect_Constructor ctor = new Target_java_lang_reflect_Constructor();
7272
ctor.constructor(declaringClass, parameterTypes, exceptionTypes, modifiers, -1, signature, annotations, parameterAnnotations);
7373
ctor.constructorAccessorFromMetadata = (Target_jdk_internal_reflect_ConstructorAccessor) accessor;
74-
SubstrateUtil.cast(ctor, Target_java_lang_reflect_Executable.class).rawParameters = rawParameters;
74+
SubstrateUtil.cast(ctor, Target_java_lang_reflect_Executable.class).parameterMetadata = parameterMetadata;
7575
Target_java_lang_reflect_AccessibleObject accessibleObject = SubstrateUtil.cast(ctor, Target_java_lang_reflect_AccessibleObject.class);
7676
accessibleObject.typeAnnotations = typeAnnotations;
7777
accessibleObject.dynamicAccessMetadata = dynamicAccessMetadata;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_Executable.java

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,18 @@
3131

3232
import org.graalvm.nativeimage.ImageSingletons;
3333

34-
import com.oracle.svm.shared.util.SubstrateUtil;
3534
import com.oracle.svm.core.annotate.Alias;
3635
import com.oracle.svm.core.annotate.Inject;
3736
import com.oracle.svm.core.annotate.RecomputeFieldValue;
3837
import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
3938
import com.oracle.svm.core.annotate.Substitute;
4039
import com.oracle.svm.core.annotate.TargetClass;
4140
import com.oracle.svm.core.hub.DynamicHub;
41+
import com.oracle.svm.core.hub.crema.CremaSupport;
4242
import com.oracle.svm.core.reflect.RuntimeMetadataDecoder;
43+
import com.oracle.svm.espresso.classfile.ConstantPool.Tag;
44+
import com.oracle.svm.espresso.classfile.attributes.MethodParametersAttribute;
45+
import com.oracle.svm.shared.util.SubstrateUtil;
4346

4447
@TargetClass(value = Executable.class)
4548
public final class Target_java_lang_reflect_Executable {
@@ -50,22 +53,33 @@ public final class Target_java_lang_reflect_Executable {
5053
@Alias @RecomputeFieldValue(kind = Kind.Reset)//
5154
Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
5255

56+
/**
57+
* Backing metadata for {@link Executable#getParameters()}.
58+
* <p>
59+
* For executables created at image-build-time this contains the encoded {@code byte[]} produced
60+
* at image build time. For run-time-loaded Crema executables this contains the
61+
* {@link MethodParametersAttribute}. A {@code null} value means there is no
62+
* {@code MethodParameters} attribute and reflection must synthesize parameter objects.
63+
*/
5364
@Inject @RecomputeFieldValue(kind = Kind.Custom, declClass = RawParametersComputer.class)//
54-
byte[] rawParameters;
65+
Object parameterMetadata;
5566

5667
@Substitute
5768
private Parameter[] getParameters0() {
58-
if (rawParameters == null) {
69+
if (parameterMetadata == null) {
5970
return null;
6071
}
61-
/*
62-
* Note that the rawParameters encoding can also encode a possible IllegalArgumentException.
63-
* We want the decoder to throw this exception. Our caller Executable.parameterData catches
64-
* it and converts it to a class format error.
65-
*/
6672
Executable executable = SubstrateUtil.cast(this, Executable.class);
6773
DynamicHub declaringClass = DynamicHub.fromClass(executable.getDeclaringClass());
68-
return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseReflectParameters(executable, rawParameters, declaringClass);
74+
if (declaringClass.isRuntimeLoaded()) {
75+
return RuntimeLoadedExecutableParameterHelper.asReflectParameters(executable, (MethodParametersAttribute) parameterMetadata, declaringClass);
76+
}
77+
/*
78+
* Note that the image-time parameter metadata encoding can also encode a possible
79+
* IllegalArgumentException. We want the decoder to throw this exception. Our caller
80+
* Executable.parameterData catches it and converts it to a MalformedParametersException.
81+
*/
82+
return ImageSingletons.lookup(RuntimeMetadataDecoder.class).parseReflectParameters(executable, (byte[]) parameterMetadata, declaringClass);
6983
}
7084

7185
@Substitute
@@ -84,3 +98,34 @@ public Object transform(Object receiver, Object originalValue) {
8498
@TargetClass(value = Executable.class, innerClass = "ParameterData")
8599
final class Target_java_lang_reflect_Executable_ParameterData {
86100
}
101+
102+
final class RuntimeLoadedExecutableParameterHelper {
103+
private RuntimeLoadedExecutableParameterHelper() {
104+
}
105+
106+
static Parameter[] asReflectParameters(Executable executable, MethodParametersAttribute methodParameters, DynamicHub declaringClass) {
107+
MethodParametersAttribute.Entry[] entries = methodParameters.getEntries();
108+
var constantPool = CremaSupport.singleton().getConstantPool(declaringClass);
109+
Parameter[] parameters = new Parameter[entries.length];
110+
int constantPoolLength = constantPool.length();
111+
for (int i = 0; i < entries.length; i++) {
112+
MethodParametersAttribute.Entry entry = entries[i];
113+
int nameIndex = entry.getNameIndex();
114+
int modifiers = entry.getAccessFlags();
115+
116+
if (nameIndex < 0 || nameIndex >= constantPoolLength) {
117+
throw new IllegalArgumentException("Constant pool index out of bounds");
118+
}
119+
120+
String name = null;
121+
if (nameIndex != 0) {
122+
if (constantPool.tagAt(nameIndex) != Tag.UTF8) {
123+
throw new IllegalArgumentException("Wrong type at constant pool index");
124+
}
125+
name = constantPool.utf8At(nameIndex, "parameter name").toString();
126+
}
127+
parameters[i] = ReflectionObjectFactory.newParameter(executable, i, name, modifiers);
128+
}
129+
return parameters;
130+
}
131+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_ReflectAccess.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public Target_java_lang_reflect_Constructor copyConstructor(Target_java_lang_ref
7979

8080
class Util_java_lang_reflect_ReflectAccess {
8181
static void copyExecutable(Target_java_lang_reflect_Executable copy, Target_java_lang_reflect_Executable executable) {
82-
copy.rawParameters = executable.rawParameters;
82+
copy.parameterMetadata = executable.parameterMetadata;
8383
copyAccessibleObject(SubstrateUtil.cast(copy, Target_java_lang_reflect_AccessibleObject.class),
8484
SubstrateUtil.cast(executable, Target_java_lang_reflect_AccessibleObject.class));
8585
}

substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/CremaResolvedJavaMethodImpl.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.oracle.svm.espresso.classfile.attributes.Attribute;
3737
import com.oracle.svm.espresso.classfile.attributes.AttributedElement;
3838
import com.oracle.svm.espresso.classfile.attributes.CodeAttribute;
39+
import com.oracle.svm.espresso.classfile.attributes.MethodParametersAttribute;
3940
import com.oracle.svm.espresso.classfile.attributes.SignatureAttribute;
4041
import com.oracle.svm.espresso.classfile.descriptors.ParserSymbols;
4142
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
@@ -160,9 +161,8 @@ public byte[] getRawAnnotationDefault() {
160161
}
161162

162163
@Override
163-
public byte[] getRawParameters() {
164-
// (GR-74007)
165-
throw VMError.unimplemented("getRawParameters");
164+
public MethodParametersAttribute getParametersAttribute() {
165+
return getAttribute(MethodParametersAttribute.NAME, MethodParametersAttribute.class);
166166
}
167167

168168
@Override

substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/CremaSupportImpl.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,9 +1738,10 @@ public void setEnterDirectInterpreterStubEntryPoint(CFunctionPointer stubEntryPo
17381738
}
17391739

17401740
@Override
1741-
public jdk.vm.ci.meta.ConstantPool getConstantPool(DynamicHub hub) {
1741+
@SuppressWarnings("unchecked")
1742+
public <T extends com.oracle.svm.espresso.classfile.ConstantPool & jdk.vm.ci.meta.ConstantPool> T getConstantPool(DynamicHub hub) {
17421743
InterpreterResolvedObjectType type = (InterpreterResolvedObjectType) hub.getInterpreterType();
17431744
assert type instanceof CremaResolvedObjectType;
1744-
return type.getConstantPool();
1745+
return (T) type.getConstantPool();
17451746
}
17461747
}

0 commit comments

Comments
 (0)