Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit 051ffce

Browse files
Ekaterina VergizovaYuri Nesterenko
authored andcommitted
8216324: GetClassMethods is confused by the presence of default methods in super interfaces
Backport-of: 277ec3d
1 parent c06b62e commit 051ffce

File tree

5 files changed

+253
-47
lines changed

5 files changed

+253
-47
lines changed

src/hotspot/share/prims/jvmtiEnv.cpp

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2487,54 +2487,54 @@ JvmtiEnv::GetClassMethods(oop k_mirror, jint* method_count_ptr, jmethodID** meth
24872487
jmethodID* result_list = (jmethodID*)jvmtiMalloc(result_length * sizeof(jmethodID));
24882488
int index;
24892489
bool jmethodids_found = true;
2490-
2491-
if (JvmtiExport::can_maintain_original_method_order()) {
2492-
// Use the original method ordering indices stored in the class, so we can emit
2493-
// jmethodIDs in the order they appeared in the class file
2494-
for (index = 0; index < result_length; index++) {
2495-
Method* m = ik->methods()->at(index);
2496-
int original_index = ik->method_ordering()->at(index);
2497-
assert(original_index >= 0 && original_index < result_length, "invalid original method index");
2498-
jmethodID id;
2499-
if (jmethodids_found) {
2500-
id = m->find_jmethod_id_or_null();
2501-
if (id == NULL) {
2502-
// If we find an uninitialized value, make sure there is
2503-
// enough space for all the uninitialized values we might
2504-
// find.
2505-
ik->ensure_space_for_methodids(index);
2506-
jmethodids_found = false;
2507-
id = m->jmethod_id();
2508-
}
2509-
} else {
2490+
int skipped = 0; // skip overpass methods
2491+
2492+
for (index = 0; index < result_length; index++) {
2493+
Method* m = ik->methods()->at(index);
2494+
// Depending on can_maintain_original_method_order capability use the original
2495+
// method ordering indices stored in the class, so we can emit jmethodIDs in
2496+
// the order they appeared in the class file or just copy in current order.
2497+
int result_index = JvmtiExport::can_maintain_original_method_order() ? ik->method_ordering()->at(index) : index;
2498+
assert(result_index >= 0 && result_index < result_length, "invalid original method index");
2499+
if (m->is_overpass()) {
2500+
result_list[result_index] = NULL;
2501+
skipped++;
2502+
continue;
2503+
}
2504+
jmethodID id;
2505+
if (jmethodids_found) {
2506+
id = m->find_jmethod_id_or_null();
2507+
if (id == NULL) {
2508+
// If we find an uninitialized value, make sure there is
2509+
// enough space for all the uninitialized values we might
2510+
// find.
2511+
ik->ensure_space_for_methodids(index);
2512+
jmethodids_found = false;
25102513
id = m->jmethod_id();
25112514
}
2512-
result_list[original_index] = id;
2515+
} else {
2516+
id = m->jmethod_id();
25132517
}
2514-
} else {
2515-
// otherwise just copy in any order
2516-
for (index = 0; index < result_length; index++) {
2517-
Method* m = ik->methods()->at(index);
2518-
jmethodID id;
2519-
if (jmethodids_found) {
2520-
id = m->find_jmethod_id_or_null();
2521-
if (id == NULL) {
2522-
// If we find an uninitialized value, make sure there is
2523-
// enough space for all the uninitialized values we might
2524-
// find.
2525-
ik->ensure_space_for_methodids(index);
2526-
jmethodids_found = false;
2527-
id = m->jmethod_id();
2528-
}
2518+
result_list[result_index] = id;
2519+
}
2520+
2521+
// Fill in return value.
2522+
if (skipped > 0) {
2523+
// copy results skipping NULL methodIDs
2524+
*methods_ptr = (jmethodID*)jvmtiMalloc((result_length - skipped) * sizeof(jmethodID));
2525+
*method_count_ptr = result_length - skipped;
2526+
for (index = 0, skipped = 0; index < result_length; index++) {
2527+
if (result_list[index] == NULL) {
2528+
skipped++;
25292529
} else {
2530-
id = m->jmethod_id();
2530+
(*methods_ptr)[index - skipped] = result_list[index];
25312531
}
2532-
result_list[index] = id;
25332532
}
2533+
deallocate((unsigned char *)result_list);
2534+
} else {
2535+
*method_count_ptr = result_length;
2536+
*methods_ptr = result_list;
25342537
}
2535-
// Fill in return value.
2536-
*method_count_ptr = result_length;
2537-
*methods_ptr = result_list;
25382538

25392539
return JVMTI_ERROR_NONE;
25402540
} /* end GetClassMethods */
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
/**
27+
* @test
28+
* @bug 8216324
29+
* @summary GetClassMethods is confused by the presence of default methods in super interfaces
30+
* @library /test/lib
31+
* @compile OverpassMethods.java
32+
* @run main/othervm/native -agentlib:OverpassMethods OverpassMethods
33+
* @run main/othervm/native -agentlib:OverpassMethods=maintain_original_method_order OverpassMethods
34+
*/
35+
36+
import java.lang.reflect.Method;
37+
import java.util.Arrays;
38+
39+
public class OverpassMethods {
40+
41+
static {
42+
try {
43+
System.loadLibrary("OverpassMethods");
44+
} catch (UnsatisfiedLinkError ex) {
45+
System.err.println("Could not load OverpassMethods library");
46+
System.err.println("java.library.path:" + System.getProperty("java.library.path"));
47+
throw ex;
48+
}
49+
}
50+
51+
static private void log(Object msg) {
52+
System.out.println(String.valueOf(msg));
53+
}
54+
55+
static private native Method[] getJVMTIDeclaredMethods(Class<?> klass);
56+
57+
public interface Parent {
58+
default String def() { return "Parent.def"; }
59+
String method0();
60+
String method1();
61+
}
62+
63+
public interface Child extends Parent {
64+
String method2();
65+
}
66+
67+
public static class Impl implements Child {
68+
public String method0() { return "Impl.method0"; }
69+
public String method1() { return "Impl.method1"; }
70+
public String method2() { return "Impl.method2"; }
71+
}
72+
73+
public static void main(String[] args) {
74+
new Impl(); // To get classes initialized
75+
76+
Method[] reflectMethods = Child.class.getDeclaredMethods();
77+
Method[] jvmtiMethods = getJVMTIDeclaredMethods(Child.class);
78+
79+
if (jvmtiMethods == null) {
80+
throw new RuntimeException("getJVMTIDeclaredMethods failed");
81+
}
82+
83+
log("Reflection getDeclaredMethods returned: " + Arrays.toString(reflectMethods));
84+
log("JVMTI GetClassMethods returned: " + Arrays.toString(jvmtiMethods));
85+
86+
if (reflectMethods.length != jvmtiMethods.length) {
87+
throw new RuntimeException("OverpassMethods failed: Unexpected method count from JVMTI GetClassMethods!");
88+
}
89+
if (!reflectMethods[0].equals(jvmtiMethods[0])) {
90+
throw new RuntimeException("OverpassMethods failed: Unexpected method from JVMTI GetClassMethods!");
91+
}
92+
log("Test passed: Got expected output from JVMTI GetClassMethods!");
93+
}
94+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
#include <stdio.h>
27+
#include <string.h>
28+
#include "jvmti.h"
29+
30+
#ifdef __cplusplus
31+
extern "C" {
32+
#endif
33+
34+
#define ACC_STATIC 0x0008
35+
36+
static jvmtiEnv *jvmti = NULL;
37+
38+
JNIEXPORT
39+
jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
40+
return JNI_VERSION_9;
41+
}
42+
43+
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
44+
vm->GetEnv((void **)&jvmti, JVMTI_VERSION_11);
45+
46+
if (options != NULL && strcmp(options, "maintain_original_method_order") == 0) {
47+
printf("Enabled capability: maintain_original_method_order\n");
48+
jvmtiCapabilities caps = {};
49+
caps.can_maintain_original_method_order = 1;
50+
51+
jvmtiError err = jvmti->AddCapabilities(&caps);
52+
if (err != JVMTI_ERROR_NONE) {
53+
printf("Agent_OnLoad: AddCapabilities failed with error: %d\n", err);
54+
return JNI_ERR;
55+
}
56+
}
57+
return JNI_OK;
58+
}
59+
60+
JNIEXPORT jobjectArray JNICALL Java_OverpassMethods_getJVMTIDeclaredMethods(JNIEnv *env, jclass static_klass, jclass klass) {
61+
jint method_count = 0;
62+
jmethodID* methods = NULL;
63+
jvmtiError err = jvmti->GetClassMethods(klass, &method_count, &methods);
64+
if (err != JVMTI_ERROR_NONE) {
65+
printf("GetClassMethods failed with error: %d\n", err);
66+
return NULL;
67+
}
68+
69+
jclass method_cls = env->FindClass("java/lang/reflect/Method");
70+
if (method_cls == NULL) {
71+
printf("FindClass (Method) failed\n");
72+
return NULL;
73+
}
74+
jobjectArray array = env->NewObjectArray(method_count, method_cls, NULL);
75+
if (array == NULL) {
76+
printf("NewObjectArray failed\n");
77+
return NULL;
78+
}
79+
80+
for (int i = 0; i < method_count; i++) {
81+
jint modifiers = 0;
82+
err = jvmti->GetMethodModifiers(methods[i], &modifiers);
83+
if (err != JVMTI_ERROR_NONE) {
84+
printf("GetMethodModifiers failed with error: %d\n", err);
85+
return NULL;
86+
}
87+
88+
jobject m = env->ToReflectedMethod(klass, methods[i], (modifiers & ACC_STATIC) == ACC_STATIC);
89+
if (array == NULL) {
90+
printf("ToReflectedMethod failed\n");
91+
return NULL;
92+
}
93+
env->SetObjectArrayElement(array, i, m);
94+
95+
env->DeleteLocalRef(m);
96+
}
97+
jvmti->Deallocate((unsigned char *)methods);
98+
99+
return array;
100+
}
101+
#ifdef __cplusplus
102+
}
103+
#endif

test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassMethods/getclmthd007.java

Lines changed: 7 additions & 2 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, 2020, 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
@@ -81,6 +81,7 @@ void meth_1(String s) {
8181
}
8282

8383
static interface InnerInterface {
84+
default void meth_def1() {}
8485
void meth_n1();
8586
}
8687

@@ -109,7 +110,11 @@ int meth_o3() {
109110
}
110111
}
111112

112-
interface OuterInterface1 {
113+
interface DefaultInterface {
114+
default void default_method() { }
115+
}
116+
117+
interface OuterInterface1 extends DefaultInterface {
113118
int meth_i1();
114119
}
115120

test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassMethods/getclmthd007/getclmthd007.cpp

Lines changed: 8 additions & 4 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, 2020, 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
@@ -54,7 +54,8 @@ static meth_info m0[] = {
5454
};
5555

5656
static meth_info m1[] = {
57-
{ "meth_n1", "()V" }
57+
{ "meth_n1", "()V" },
58+
{ "meth_def1", "()V" }
5859
};
5960

6061
static meth_info m2[] = {
@@ -98,7 +99,7 @@ static meth_info m9[] = {
9899

99100
static class_info classes[] = {
100101
{ "InnerClass1", 2, m0 },
101-
{ "InnerInterface", 1, m1 },
102+
{ "InnerInterface", 2, m1 },
102103
{ "InnerClass2", 4, m2 },
103104
{ "OuterClass1", 1, m3 },
104105
{ "OuterClass2", 2, m4 },
@@ -145,6 +146,7 @@ Java_nsk_jvmti_GetClassMethods_getclmthd007_check(JNIEnv *env,
145146
char *name, *sig, *generic;
146147
int j, k;
147148

149+
int failed = JNI_FALSE; // enable debugging on failure
148150
if (jvmti == NULL) {
149151
printf("JVMTI client was not properly loaded!\n");
150152
result = STATUS_FAILED;
@@ -167,12 +169,14 @@ Java_nsk_jvmti_GetClassMethods_getclmthd007_check(JNIEnv *env,
167169
printf("(%d) wrong number of methods: %d, expected: %d\n",
168170
i, mcount, classes[i].mcount);
169171
result = STATUS_FAILED;
172+
failed = JNI_TRUE; // show the methods found
173+
printf(">>> %s:\n", classes[i].name);
170174
}
171175
for (k = 0; k < mcount; k++) {
172176
if (methods[k] == NULL) {
173177
printf("(%d:%d) methodID = null\n", i, k);
174178
result = STATUS_FAILED;
175-
} else if (printdump == JNI_TRUE) {
179+
} else if (printdump == JNI_TRUE || failed == JNI_TRUE) {
176180
err = jvmti->GetMethodName(methods[k],
177181
&name, &sig, &generic);
178182
if (err == JVMTI_ERROR_NONE) {

0 commit comments

Comments
 (0)