diff --git a/src/hotspot/share/runtime/reflectionUtils.hpp b/src/hotspot/share/runtime/reflectionUtils.hpp index 04ff68c4271..93bb541467a 100644 --- a/src/hotspot/share/runtime/reflectionUtils.hpp +++ b/src/hotspot/share/runtime/reflectionUtils.hpp @@ -214,20 +214,26 @@ class FilteredFieldStream : public FieldStream { private: int _filtered_fields_count; bool has_filtered_field() { return (_filtered_fields_count > 0); } + void skip_filtered_fields() { + if (has_filtered_field()) { + while (_index >= 0 && FilteredFieldsMap::is_filtered_field((Klass*)_klass, offset())) { + _index -= 1; + } + } + } public: FilteredFieldStream(InstanceKlass* klass, bool local_only, bool classes_only) : FieldStream(klass, local_only, classes_only) { _filtered_fields_count = FilteredFieldsMap::filtered_fields_count(klass, local_only); + // skip filtered fields at the end + skip_filtered_fields(); + } int field_count(); void next() { _index -= 1; - if (has_filtered_field()) { - while (_index >=0 && FilteredFieldsMap::is_filtered_field((Klass*)_klass, offset())) { - _index -= 1; - } - } + skip_filtered_fields(); } }; diff --git a/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/FilteredFieldsTest.java b/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/FilteredFieldsTest.java new file mode 100644 index 00000000000..3e77845e457 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/FilteredFieldsTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8318626 + * @summary Verifies JVMTI GetClassFields function filters out fields + * the same way Class.getDeclaredFields() does. + * + * @run main/othervm/native -agentlib:FilteredFieldsTest FilteredFieldsTest + */ + +import java.lang.reflect.Field; + +public class FilteredFieldsTest { + + static { + System.loadLibrary("FilteredFieldsTest"); + } + + private native static int getJVMTIFieldCount(Class cls); + + private static int getDeclaredFieldsCount(Class cls) { + Field[] declaredFields = cls.getDeclaredFields(); + System.out.println("Class.getDeclaredFields reported " + declaredFields.length + " fields:"); + for (int i = 0; i < declaredFields.length; i++) { + System.out.println(" [" + i + "] : " + declaredFields[i]); + } + return declaredFields.length; + } + + public static void main(String args[]) throws Exception { + Class cls = Class.forName("jdk.internal.reflect.ConstantPool"); + int declaredCount = getDeclaredFieldsCount(cls); + int jvmtiCount = getJVMTIFieldCount(cls); + if (declaredCount != jvmtiCount) { + throw new Exception("declaredCount != jvmtiCount: " + declaredCount + " != " + jvmtiCount); + } + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp new file mode 100644 index 00000000000..521242a1c29 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/GetClassFields/FilteredFields/libFilteredFieldsTest.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "jvmti.h" +#include "jvmti_common.h" + +extern "C" { + +static jvmtiEnv *jvmti = NULL; + + +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { + jint res = jvm->GetEnv((void **)&jvmti, JVMTI_VERSION_1_1); + if (res != JNI_OK || jvmti == NULL) { + printf("Wrong result of a valid call to GetEnv!\n"); + fflush(0); + return JNI_ERR; + } + return JNI_OK; +} + +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} +JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + + +JNIEXPORT jint JNICALL +Java_FilteredFieldsTest_getJVMTIFieldCount(JNIEnv *env, jclass cls, jclass clazz) { + if (jvmti == NULL) { + env->FatalError("JVMTI agent was not properly loaded"); + } + + jint fcount = 0; + jfieldID *fields = nullptr; + + check_jvmti_status(env, jvmti->GetClassFields(clazz, &fcount, &fields), "GetClassFields failed"); + + printf("GetClassFields returned %d fields:\n", (int)fcount); + for (int i = 0; i < fcount; i++) { + char *name; + jvmtiError err = jvmti->GetFieldName(clazz, fields[i], &name, nullptr, nullptr); + if (err != JVMTI_ERROR_NONE) { + printf("GetFieldName(%d) returned error: %s (%d)\n", + i, TranslateError(err), err); + continue; + } + printf(" [%d]: %s\n", i, name); + jvmti->Deallocate((unsigned char *)name); + } + fflush(0); + return fcount; +} + +}