Skip to content

Commit 599560a

Browse files
author
Alex Menkov
committed
8317635: Improve GetClassFields test to verify correctness of field order
Reviewed-by: cjplummer, sspitsyn
1 parent 9cf334f commit 599560a

File tree

3 files changed

+124
-114
lines changed

3 files changed

+124
-114
lines changed

test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007.java

Lines changed: 69 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,15 @@
2424
package nsk.jvmti.GetClassFields;
2525

2626
import java.io.PrintStream;
27+
import java.io.InputStream;
28+
import java.util.List;
29+
import java.util.ArrayList;
30+
31+
import jdk.internal.org.objectweb.asm.ClassReader;
32+
import jdk.internal.org.objectweb.asm.ClassVisitor;
33+
import jdk.internal.org.objectweb.asm.FieldVisitor;
34+
import jdk.internal.org.objectweb.asm.Opcodes;
35+
2736

2837
public class getclfld007 {
2938

@@ -40,7 +49,7 @@ public class getclfld007 {
4049
}
4150
}
4251

43-
native static void check(int i, Class cls);
52+
native static void check(Class cls, String[] expectedFields);
4453
native static int getRes();
4554

4655
public static void main(String args[]) {
@@ -52,22 +61,64 @@ public static void main(String args[]) {
5261

5362
public static int run(String args[], PrintStream out) {
5463
try {
55-
check(0, Class.forName(InnerClass1.class.getName()));
56-
check(1, Class.forName(InnerInterface.class.getName()));
57-
check(2, Class.forName(InnerClass2.class.getName()));
58-
check(3, Class.forName(OuterClass1.class.getName()));
59-
check(4, Class.forName(OuterClass2.class.getName()));
60-
check(5, Class.forName(OuterClass3.class.getName()));
61-
check(6, Class.forName(OuterInterface1.class.getName()));
62-
check(7, Class.forName(OuterInterface2.class.getName()));
63-
check(8, Class.forName(OuterClass4.class.getName()));
64-
check(9, Class.forName(OuterClass5.class.getName()));
65-
} catch (ClassNotFoundException e) {
64+
check(Class.forName(InnerClass1.class.getName()));
65+
check(Class.forName(InnerInterface.class.getName()));
66+
check(Class.forName(InnerClass2.class.getName()));
67+
check(Class.forName(OuterClass1.class.getName()));
68+
check(Class.forName(OuterClass2.class.getName()));
69+
check(Class.forName(OuterClass3.class.getName()));
70+
check(Class.forName(OuterInterface1.class.getName()));
71+
check(Class.forName(OuterInterface2.class.getName()));
72+
check(Class.forName(OuterClass4.class.getName()));
73+
check(Class.forName(OuterClass5.class.getName()));
74+
} catch (Exception e) {
6675
throw new RuntimeException(e);
6776
}
6877
return getRes();
6978
}
7079

80+
81+
static void check(Class cls) throws Exception {
82+
FieldExplorer explorer = new FieldExplorer(cls);
83+
List<String> fields = explorer.get();
84+
check(cls, fields.toArray(new String[0]));
85+
}
86+
87+
// helper class to get list of the class fields
88+
// in the order they appear in the class file
89+
static class FieldExplorer extends ClassVisitor {
90+
private final Class cls;
91+
private List<String> fieldNameAndSig = new ArrayList<>();
92+
private FieldExplorer(Class cls) {
93+
super(Opcodes.ASM7);
94+
this.cls = cls;
95+
}
96+
97+
@Override
98+
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
99+
System.out.println(" field '" + name + "', type = " + descriptor);
100+
fieldNameAndSig.add(name);
101+
fieldNameAndSig.add(descriptor);
102+
return super.visitField(access, name, descriptor, signature, value);
103+
}
104+
105+
private InputStream getClassBytes() throws Exception {
106+
String clsName = cls.getName();
107+
String clsPath = clsName.replace('.', '/') + ".class";
108+
return cls.getClassLoader().getResourceAsStream(clsPath);
109+
}
110+
111+
// each field is represented by 2 Strings in the list: name and type descriptor
112+
public List<String> get() throws Exception {
113+
System.out.println("Class " + cls.getName());
114+
try (InputStream classBytes = getClassBytes()) {
115+
ClassReader classReader = new ClassReader(classBytes);
116+
classReader.accept(this, 0);
117+
}
118+
return fieldNameAndSig;
119+
}
120+
}
121+
71122
static class InnerClass1 {
72123
String fld_1;
73124
void meth(String s) {
@@ -119,8 +170,13 @@ public int meth_i2() {
119170
}
120171
}
121172

173+
// class with multiple fields to verify correctness of the field order
122174
class OuterClass5 extends OuterClass4 {
123175
int fld_i1 = 1;
176+
String fld_s1 = "str";
177+
int fld_i2 = 2;
178+
String fld_s2 = "str2";
179+
124180
public int meth_i1() {
125181
return 1;
126182
}

test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/TestDescription.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -31,9 +31,9 @@
3131
* DESCRIPTION
3232
* The test exercises JVMTI function
3333
* GetClassFields(clazz, fieldCountPtr, fieldsPtr).
34-
* The test checks if the function returns the expected list of fields.
35-
* That is the field list contains only directly declared (not inherited)
36-
* fields.
34+
* The test checks if the function returns the expected list of fields:
35+
* - the list contains only directly declared (not inherited) fields;
36+
* - fields are returned in the order they occur in the class file.
3737
* COMMENTS
3838
* Ported from JVMDI.
3939
* Test fixed due to test bug:
@@ -45,6 +45,7 @@
4545
*
4646
* @library /vmTestbase
4747
* /test/lib
48+
* @modules java.base/jdk.internal.org.objectweb.asm
4849
* @run main/othervm/native -agentlib:getclfld007 nsk.jvmti.GetClassFields.getclfld007
4950
*/
5051

test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp

Lines changed: 50 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -33,69 +33,25 @@ extern "C" {
3333
#define PASSED 0
3434
#define STATUS_FAILED 2
3535

36-
typedef struct {
37-
const char *name;
38-
const char *sig;
39-
} fld_info;
40-
41-
typedef struct {
42-
const char *name;
43-
jint fcount;
44-
fld_info *flds;
45-
} class_info;
46-
4736
static jvmtiEnv *jvmti = NULL;
4837
static jint result = PASSED;
49-
static jboolean printdump = JNI_FALSE;
50-
51-
static fld_info f0[] = {
52-
{ "fld_1", "Ljava/lang/String;" }
53-
};
54-
55-
static fld_info f1[] = {
56-
{ "fld_n1", "I" }
57-
};
58-
59-
static fld_info f2[] = {
60-
{ "fld_n2", "I" }
61-
};
62-
63-
static fld_info f4[] = {
64-
{ "fld_o2", "I" }
65-
};
66-
67-
static fld_info f5[] = {
68-
{ "fld_o3", "I" }
69-
};
70-
71-
static fld_info f6[] = {
72-
{ "fld_i1", "I" }
73-
};
74-
75-
static fld_info f7[] = {
76-
{ "fld_i2", "I" }
77-
};
78-
79-
static fld_info f8[] = {
80-
{ "fld_i2", "I" }
81-
};
82-
83-
static fld_info f9[] = {
84-
{ "fld_i1", "I" }
85-
};
86-
87-
static class_info classes[] = {
88-
{ "InnerClass1", 1, f0 },
89-
{ "InnerInterface", 1, f1 },
90-
{ "InnerClass2", 1, f2 },
91-
{ "OuterClass1", 0, NULL },
92-
{ "OuterClass2", 1, f4 },
93-
{ "OuterClass3", 1, f5 },
94-
{ "OuterInterface1", 1, f6 },
95-
{ "OuterInterface2", 1, f7 },
96-
{ "OuterClass4", 1, f8 },
97-
{ "OuterClass5", 1, f9 }
98-
};
38+
39+
40+
// compares 'value' with jobject_arr[index]
41+
static bool equals_str(JNIEnv *env, const char *value, jobjectArray jobject_arr, jint index) {
42+
jstring jstr = (jstring)env->GetObjectArrayElement(jobject_arr, index);
43+
const char* utf = env->GetStringUTFChars(jstr, NULL);
44+
bool res = false;
45+
if (utf != NULL) {
46+
res = strcmp(value, utf) == 0;
47+
env->ReleaseStringUTFChars(jstr, utf);
48+
} else {
49+
printf("GetStringUTFChars failed\n");
50+
result = STATUS_FAILED;
51+
}
52+
env->DeleteLocalRef(jstr);
53+
return res;
54+
}
9955

10056
#ifdef STATIC_BUILD
10157
JNIEXPORT jint JNICALL Agent_OnLoad_getclfld007(JavaVM *jvm, char *options, void *reserved) {
@@ -111,10 +67,6 @@ JNIEXPORT jint JNI_OnLoad_getclfld007(JavaVM *jvm, char *options, void *reserved
11167
jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
11268
jint res;
11369

114-
if (options != NULL && strcmp(options, "printdump") == 0) {
115-
printdump = JNI_TRUE;
116-
}
117-
11870
res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1);
11971
if (res != JNI_OK || jvmti == NULL) {
12072
printf("Wrong result of a valid call to GetEnv!\n");
@@ -125,61 +77,62 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
12577
}
12678

12779
JNIEXPORT void JNICALL
128-
Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jint i, jclass clazz) {
80+
Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jclass clazz, jobjectArray fieldArr) {
12981
jvmtiError err;
13082
jint fcount;
13183
jfieldID *fields;
132-
char *name, *sig, *generic;
84+
char *name, *sig;
13385
int j;
13486

13587
if (jvmti == NULL) {
13688
printf("JVMTI client was not properly loaded!\n");
89+
fflush(0);
13790
result = STATUS_FAILED;
13891
return;
13992
}
14093

141-
if (printdump == JNI_TRUE) {
142-
printf(">>> %s:\n", classes[i].name);
143-
}
94+
// fieldArr contains 2 elements for each field
95+
jint field_count = env->GetArrayLength(fieldArr) / 2;
14496

14597
err = jvmti->GetClassFields(clazz, &fcount, &fields);
14698
if (err != JVMTI_ERROR_NONE) {
147-
printf("(GetClassFields#%d) unexpected error: %s (%d)\n",
148-
i, TranslateError(err), err);
99+
printf("GetClassFields unexpected error: %s (%d)\n",
100+
TranslateError(err), err);
101+
fflush(0);
149102
result = STATUS_FAILED;
150103
return;
151104
}
152105

153-
if (fcount != classes[i].fcount) {
154-
printf("(%d) wrong number of fields: %d, expected: %d\n",
155-
i, fcount, classes[i].fcount);
106+
if (fcount != field_count) {
107+
printf("wrong number of fields: %d, expected: %d\n",
108+
fcount, field_count);
156109
result = STATUS_FAILED;
157110
}
158111
for (j = 0; j < fcount; j++) {
159112
if (fields[j] == NULL) {
160-
printf("(%d:%d) fieldID = null\n", i, j);
161-
} else {
162-
err = jvmti->GetFieldName(clazz, fields[j],
163-
&name, &sig, &generic);
164-
if (err != JVMTI_ERROR_NONE) {
165-
printf("(GetFieldName#%d:%d) unexpected error: %s (%d)\n",
166-
i, j, TranslateError(err), err);
167-
} else {
168-
if (printdump == JNI_TRUE) {
169-
printf(">>> [%d]: %s, sig = \"%s\"\n", j, name, sig);
170-
}
171-
if ((j < classes[i].fcount) &&
172-
(name == NULL || sig == NULL ||
173-
strcmp(name, classes[i].flds[j].name) != 0 ||
174-
strcmp(sig, classes[i].flds[j].sig) != 0)) {
175-
printf("(%d:%d) wrong field: \"%s%s\"", i, j, name, sig);
176-
printf(", expected: \"%s%s\"\n",
177-
classes[i].flds[j].name, classes[i].flds[j].sig);
178-
result = STATUS_FAILED;
179-
}
180-
}
113+
printf("(%d) fieldID = null\n", j);
114+
result = STATUS_FAILED;
115+
continue;
116+
}
117+
err = jvmti->GetFieldName(clazz, fields[j], &name, &sig, NULL);
118+
if (err != JVMTI_ERROR_NONE) {
119+
printf("(GetFieldName#%d) unexpected error: %s (%d)\n",
120+
j, TranslateError(err), err);
121+
result = STATUS_FAILED;
122+
continue;
123+
}
124+
printf(">>> [%d]: %s, sig = \"%s\"\n", j, name, sig);
125+
if ((j < field_count) &&
126+
(name == NULL || sig == NULL ||
127+
!equals_str(env, name, fieldArr, j * 2) ||
128+
!equals_str(env, sig, fieldArr, j * 2 + 1))) {
129+
printf("(%d) wrong field: \"%s%s\"", j, name, sig);
130+
result = STATUS_FAILED;
181131
}
132+
jvmti->Deallocate((unsigned char *)name);
133+
jvmti->Deallocate((unsigned char *)sig);
182134
}
135+
fflush(0);
183136
}
184137

185138
JNIEXPORT int JNICALL

0 commit comments

Comments
 (0)