diff --git a/src/hotspot/share/c1/c1_Canonicalizer.cpp b/src/hotspot/share/c1/c1_Canonicalizer.cpp index 9a8d517822fcc..9702b89a5c8f2 100644 --- a/src/hotspot/share/c1/c1_Canonicalizer.cpp +++ b/src/hotspot/share/c1/c1_Canonicalizer.cpp @@ -547,22 +547,6 @@ void Canonicalizer::do_Intrinsic (Intrinsic* x) { } break; } - case vmIntrinsics::_getModifiers: { - assert(x->number_of_arguments() == 1, "wrong type"); - - // Optimize for Foo.class.getModifier() - InstanceConstant* c = x->argument_at(0)->type()->as_InstanceConstant(); - if (c != nullptr && !c->value()->is_null_object()) { - ciType* t = c->value()->java_mirror_type(); - if (t->is_klass()) { - set_constant(t->as_klass()->modifier_flags()); - } else { - assert(t->is_primitive_type(), "should be a primitive type"); - set_constant(JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC); - } - } - break; - } default: break; } diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp index a07a92b4419ae..7d2e6ee75d9ae 100644 --- a/src/hotspot/share/c1/c1_Compiler.cpp +++ b/src/hotspot/share/c1/c1_Compiler.cpp @@ -156,7 +156,6 @@ bool Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_getClass: case vmIntrinsics::_isInstance: case vmIntrinsics::_isPrimitive: - case vmIntrinsics::_getModifiers: case vmIntrinsics::_currentCarrierThread: case vmIntrinsics::_currentThread: case vmIntrinsics::_scopedValueCache: diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 930e5e9df1bf7..4c3cf20cbf6c1 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -1303,42 +1303,6 @@ void LIRGenerator::do_isPrimitive(Intrinsic* x) { __ cmove(lir_cond_notEqual, LIR_OprFact::intConst(0), LIR_OprFact::intConst(1), result, T_BOOLEAN); } -// Example: Foo.class.getModifiers() -void LIRGenerator::do_getModifiers(Intrinsic* x) { - assert(x->number_of_arguments() == 1, "wrong type"); - - LIRItem receiver(x->argument_at(0), this); - receiver.load_item(); - LIR_Opr result = rlock_result(x); - - CodeEmitInfo* info = nullptr; - if (x->needs_null_check()) { - info = state_for(x); - } - - // While reading off the universal constant mirror is less efficient than doing - // another branch and returning the constant answer, this branchless code runs into - // much less risk of confusion for C1 register allocator. The choice of the universe - // object here is correct as long as it returns the same modifiers we would expect - // from the primitive class itself. See spec for Class.getModifiers that provides - // the typed array klasses with similar modifiers as their component types. - - Klass* univ_klass = Universe::byteArrayKlass(); - assert(univ_klass->modifier_flags() == (JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC), "Sanity"); - LIR_Opr prim_klass = LIR_OprFact::metadataConst(univ_klass); - - LIR_Opr recv_klass = new_register(T_METADATA); - __ move(new LIR_Address(receiver.result(), java_lang_Class::klass_offset(), T_ADDRESS), recv_klass, info); - - // Check if this is a Java mirror of primitive type, and select the appropriate klass. - LIR_Opr klass = new_register(T_METADATA); - __ cmp(lir_cond_equal, recv_klass, LIR_OprFact::metadataConst(nullptr)); - __ cmove(lir_cond_equal, prim_klass, recv_klass, klass, T_ADDRESS); - - // Get the answer. - __ move(new LIR_Address(klass, in_bytes(Klass::modifier_flags_offset()), T_CHAR), result); -} - void LIRGenerator::do_getObjectSize(Intrinsic* x) { assert(x->number_of_arguments() == 3, "wrong type"); LIR_Opr result_reg = rlock_result(x); @@ -2957,7 +2921,6 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { case vmIntrinsics::_Object_init: do_RegisterFinalizer(x); break; case vmIntrinsics::_isInstance: do_isInstance(x); break; case vmIntrinsics::_isPrimitive: do_isPrimitive(x); break; - case vmIntrinsics::_getModifiers: do_getModifiers(x); break; case vmIntrinsics::_getClass: do_getClass(x); break; case vmIntrinsics::_getObjectSize: do_getObjectSize(x); break; case vmIntrinsics::_currentCarrierThread: do_currentCarrierThread(x); break; diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp index a66758054d7d4..58a0091b0b553 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.hpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, 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 @@ -255,7 +255,6 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void do_RegisterFinalizer(Intrinsic* x); void do_isInstance(Intrinsic* x); void do_isPrimitive(Intrinsic* x); - void do_getModifiers(Intrinsic* x); void do_getClass(Intrinsic* x); void do_getObjectSize(Intrinsic* x); void do_currentCarrierThread(Intrinsic* x); diff --git a/src/hotspot/share/ci/ciKlass.hpp b/src/hotspot/share/ci/ciKlass.hpp index 7b8d871eb561f..80cc0fb840b80 100644 --- a/src/hotspot/share/ci/ciKlass.hpp +++ b/src/hotspot/share/ci/ciKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, 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 @@ -122,7 +122,7 @@ class ciKlass : public ciType { // Get the instance of java.lang.Class corresponding to this klass. ciInstance* java_mirror(); - // Fetch Klass::modifier_flags. + // Fetch modifier flags. jint modifier_flags(); // Fetch Klass::access_flags. diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 92d31c48ca814..ae66ee22511eb 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -3747,11 +3747,6 @@ void ClassFileParser::apply_parsed_class_metadata( this_klass->set_permitted_subclasses(_permitted_subclasses); this_klass->set_record_components(_record_components); - // Initialize cached modifier_flags to support Class.getModifiers(). - // This must follow setting inner_class attributes. - u2 computed_modifiers = this_klass->compute_modifier_flags(); - this_klass->set_modifier_flags(computed_modifiers); - // Delay the setting of _local_interfaces and _transitive_interfaces until after // initialize_supers() in fill_instance_klass(). It is because the _local_interfaces could // be shared with _transitive_interfaces and _transitive_interfaces may be shared with diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index a9e683900199f..c286a33c17aa0 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -867,6 +867,7 @@ int java_lang_Class::_source_file_offset; int java_lang_Class::_classData_offset; int java_lang_Class::_classRedefinedCount_offset; int java_lang_Class::_reflectionData_offset; +int java_lang_Class::_modifiers_offset; bool java_lang_Class::_offsets_computed = false; GrowableArray* java_lang_Class::_fixup_mirror_list = nullptr; @@ -1060,6 +1061,10 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // Setup indirection from mirror->klass set_klass(mirror(), k); + // Set the modifiers flag. + int computed_modifiers = k->compute_modifier_flags(); + set_modifiers(mirror(), computed_modifiers); + InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass()); assert(oop_size(mirror()) == mk->instance_size(k), "should have been set"); @@ -1355,6 +1360,7 @@ oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, Basic InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(vmClasses::Class_klass()); assert(static_oop_field_count(java_class) == 0, "should have been zeroed by allocation"); #endif + set_modifiers(java_class, JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC); return java_class; } @@ -1493,7 +1499,8 @@ oop java_lang_Class::primitive_mirror(BasicType t) { macro(_name_offset, k, "name", string_signature, false); \ macro(_classData_offset, k, "classData", object_signature, false); \ macro(_reflectionData_offset, k, "reflectionData", java_lang_ref_SoftReference_signature, false); \ - macro(_signers_offset, k, "signers", object_array_signature, false); + macro(_signers_offset, k, "signers", object_array_signature, false); \ + macro(_modifiers_offset, k, vmSymbols::modifiers_name(), int_signature, false); void java_lang_Class::compute_offsets() { if (_offsets_computed) { @@ -1527,6 +1534,16 @@ void java_lang_Class::set_classRedefinedCount(oop the_class_mirror, int value) { the_class_mirror->int_field_put(_classRedefinedCount_offset, value); } +int java_lang_Class::modifiers(oop the_class_mirror) { + assert(_modifiers_offset != 0, "offsets should have been initialized"); + return the_class_mirror->int_field(_modifiers_offset); +} + +void java_lang_Class::set_modifiers(oop the_class_mirror, int value) { + assert(_modifiers_offset != 0, "offsets should have been initialized"); + the_class_mirror->int_field_put(_modifiers_offset, value); +} + // Note: JDK1.1 and before had a privateInfo_offset field which was used for the // platform thread structure, and a eetop offset which was used for thread diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index bac6b86fd803a..317c4752f56ed 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -257,6 +257,7 @@ class java_lang_Class : AllStatic { static int _classData_offset; static int _classRedefinedCount_offset; static int _reflectionData_offset; + static int _modifiers_offset; static bool _offsets_computed; @@ -337,6 +338,9 @@ class java_lang_Class : AllStatic { static oop source_file(oop java_class); static void set_source_file(oop java_class, oop source_file); + static int modifiers(oop java_class); + static void set_modifiers(oop java_class, int value); + static size_t oop_size(oop java_class); static void set_oop_size(HeapWord* java_class, size_t size); static int static_oop_field_count(oop java_class); diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index 4357e44e18761..aaeb54f0d32fe 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -256,7 +256,6 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { switch (id) { case vmIntrinsics::_isInstance: case vmIntrinsics::_isAssignableFrom: - case vmIntrinsics::_getModifiers: case vmIntrinsics::_isInterface: case vmIntrinsics::_isArray: case vmIntrinsics::_isPrimitive: diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 6ec0222324e06..16f6ff024d0c6 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -304,8 +304,6 @@ class methodHandle; do_name( isAssignableFrom_name, "isAssignableFrom") \ do_intrinsic(_isInstance, java_lang_Class, isInstance_name, object_boolean_signature, F_RN) \ do_name( isInstance_name, "isInstance") \ - do_intrinsic(_getModifiers, java_lang_Class, getModifiers_name, void_int_signature, F_RN) \ - do_name( getModifiers_name, "getModifiers") \ do_intrinsic(_isInterface, java_lang_Class, isInterface_name, void_boolean_signature, F_RN) \ do_name( isInterface_name, "isInterface") \ do_intrinsic(_isArray, java_lang_Class, isArray_name, void_boolean_signature, F_RN) \ diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 96d369678f792..8c964b5693169 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -272,7 +272,6 @@ nonstatic_field(Klass, _name, Symbol*) \ volatile_nonstatic_field(Klass, _next_sibling, Klass*) \ nonstatic_field(Klass, _java_mirror, OopHandle) \ - nonstatic_field(Klass, _modifier_flags, u2) \ nonstatic_field(Klass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _class_loader_data, ClassLoaderData*) \ nonstatic_field(Klass, _secondary_supers_bitmap, uintx) \ diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 40e5e62dbc715..9f166e13751a7 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -328,6 +328,12 @@ jint Klass::array_layout_helper(BasicType etype) { return lh; } +int Klass::modifier_flags() const { + int mods = java_lang_Class::modifiers(java_mirror()); + assert(mods == compute_modifier_flags(), "should be same"); + return mods; +} + bool Klass::can_be_primary_super_slow() const { if (super() == nullptr) return true; diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index a3e1e4524795f..9ea021713fc42 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -123,9 +123,6 @@ class Klass : public Metadata { AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. // Some flags created by the JVM, not in the class file itself, // are in _misc_flags below. - // Processed access flags, for use by Class.getModifiers. - u2 _modifier_flags; - KlassFlags _misc_flags; // The fields _super_check_offset, _secondary_super_cache, _secondary_supers @@ -292,10 +289,6 @@ class Klass : public Metadata { // This leaves the OopHandle in the CLD, but that's ok, you can't release them. void clear_java_mirror_handle() { _java_mirror = OopHandle(); } - // modifier flags - u2 modifier_flags() const { return _modifier_flags; } - void set_modifier_flags(u2 flags) { _modifier_flags = flags; } - // size helper int layout_helper() const { return _layout_helper; } void set_layout_helper(int lh) { _layout_helper = lh; } @@ -448,7 +441,6 @@ class Klass : public Metadata { static ByteSize secondary_supers_offset() { return byte_offset_of(Klass, _secondary_supers); } static ByteSize java_mirror_offset() { return byte_offset_of(Klass, _java_mirror); } static ByteSize class_loader_data_offset() { return byte_offset_of(Klass, _class_loader_data); } - static ByteSize modifier_flags_offset() { return byte_offset_of(Klass, _modifier_flags); } static ByteSize layout_helper_offset() { return byte_offset_of(Klass, _layout_helper); } static ByteSize access_flags_offset() { return byte_offset_of(Klass, _access_flags); } #if INCLUDE_JVMCI @@ -758,6 +750,7 @@ class Klass : public Metadata { public: virtual u2 compute_modifier_flags() const = 0; + int modifier_flags() const; // JVMTI support virtual jint jvmti_class_status() const; diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp index 288a1ed359bbd..7af6b963052f1 100644 --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -139,9 +139,6 @@ ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name) : ArrayK set_layout_helper(array_layout_helper(T_OBJECT)); assert(is_array_klass(), "sanity"); assert(is_objArray_klass(), "sanity"); - - // Compute modifier flags after bottom_klass and element_klass are initialized. - set_modifier_flags(compute_modifier_flags()); } size_t ObjArrayKlass::oop_size(oop obj) const { diff --git a/src/hotspot/share/oops/typeArrayKlass.cpp b/src/hotspot/share/oops/typeArrayKlass.cpp index 95377a8452df4..39385bb0184e7 100644 --- a/src/hotspot/share/oops/typeArrayKlass.cpp +++ b/src/hotspot/share/oops/typeArrayKlass.cpp @@ -87,9 +87,6 @@ TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name, assert(size() >= TypeArrayKlass::header_size(), "bad size"); set_class_loader_data(ClassLoaderData::the_null_class_loader_data()); - - // Compute modifier flags. - set_modifier_flags(compute_modifier_flags()); } typeArrayOop TypeArrayKlass::allocate_common(int length, bool do_zero, TRAPS) { diff --git a/src/hotspot/share/oops/typeArrayKlass.hpp b/src/hotspot/share/oops/typeArrayKlass.hpp index 6ec72ae49c0c8..fa4e301e3e446 100644 --- a/src/hotspot/share/oops/typeArrayKlass.hpp +++ b/src/hotspot/share/oops/typeArrayKlass.hpp @@ -51,6 +51,8 @@ class TypeArrayKlass : public ArrayKlass { jint max_length() { return _max_length; } void set_max_length(jint m) { _max_length = m; } + u2 compute_modifier_flags() const; + // testers DEBUG_ONLY(bool is_typeArray_klass_slow() const { return true; }) @@ -73,8 +75,6 @@ class TypeArrayKlass : public ArrayKlass { // Copying void copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS); - u2 compute_modifier_flags() const; - // Oop iterators. Since there are no oops in TypeArrayKlasses, // these functions only return the size of the object. diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 40b43e383dc75..e126697ed05d3 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -749,7 +749,6 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_clone: case vmIntrinsics::_isAssignableFrom: case vmIntrinsics::_isInstance: - case vmIntrinsics::_getModifiers: case vmIntrinsics::_isInterface: case vmIntrinsics::_isArray: case vmIntrinsics::_isPrimitive: diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 8fb1eda0001f5..7a03ac418a892 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1699,8 +1699,6 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr } if (flat->offset() == in_bytes(Klass::super_check_offset_offset())) alias_type(idx)->set_rewritable(false); - if (flat->offset() == in_bytes(Klass::modifier_flags_offset())) - alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::access_flags_offset())) alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::misc_flags_offset())) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 7ef030ccd7d4d..c7eed427504be 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -515,7 +515,6 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_isAssignableFrom: return inline_native_subtype_check(); case vmIntrinsics::_isInstance: - case vmIntrinsics::_getModifiers: case vmIntrinsics::_isInterface: case vmIntrinsics::_isArray: case vmIntrinsics::_isPrimitive: @@ -3891,10 +3890,6 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { prim_return_value = intcon(0); obj = argument(1); break; - case vmIntrinsics::_getModifiers: - prim_return_value = intcon(JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC); - return_type = TypeInt::CHAR; - break; case vmIntrinsics::_isInterface: prim_return_value = intcon(0); break; @@ -3974,11 +3969,6 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { query_value = gen_instanceof(obj, kls, safe_for_replace); break; - case vmIntrinsics::_getModifiers: - p = basic_plus_adr(kls, in_bytes(Klass::modifier_flags_offset())); - query_value = make_load(nullptr, p, TypeInt::CHAR, T_CHAR, MemNode::unordered); - break; - case vmIntrinsics::_isInterface: // (To verify this code sequence, check the asserts in JVM_IsInterface.) if (generate_interface_guard(kls, region) != nullptr) diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index a5a746626f8c5..438e645b2494b 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1972,12 +1972,6 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, ciKlass* klass) const { assert(!UseCompactObjectHeaders || tkls->offset() != in_bytes(Klass::prototype_header_offset()), "must not happen"); - if (tkls->offset() == in_bytes(Klass::modifier_flags_offset())) { - // The field is Klass::_modifier_flags. Return its (constant) value. - // (Folds up the 2nd indirection in aClassConstant.getModifiers().) - assert(Opcode() == Op_LoadUS, "must load an unsigned short from _modifier_flags"); - return TypeInt::make(klass->modifier_flags()); - } if (tkls->offset() == in_bytes(Klass::access_flags_offset())) { // The field is Klass::_access_flags. Return its (constant) value. // (Folds up the 2nd indirection in Reflection.getClassAccessFlags(aClassConstant).) @@ -2461,7 +2455,7 @@ const Type* LoadNode::klass_value_common(PhaseGVN* phase) const { // a primitive Class (e.g., int.class) has null for a klass field return TypePtr::NULL_PTR; } - // (Folds up the 1st indirection in aClassConstant.getModifiers().) + // Fold up the load of the hidden field return TypeKlassPtr::make(t->as_klass(), Type::trust_interfaces); } // non-constant mirror, so we can't tell what's going on diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index c4803fcfd4af9..9826414a8fcb9 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1297,22 +1297,6 @@ JVM_ENTRY(jboolean, JVM_IsPrimitiveClass(JNIEnv *env, jclass cls)) JVM_END -JVM_ENTRY(jint, JVM_GetClassModifiers(JNIEnv *env, jclass cls)) - oop mirror = JNIHandles::resolve_non_null(cls); - if (java_lang_Class::is_primitive(mirror)) { - // Primitive type - return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC; - } - - Klass* k = java_lang_Class::as_Klass(mirror); - debug_only(u2 computed_modifiers = k->compute_modifier_flags()); - assert(k->modifier_flags() == computed_modifiers, "modifiers cache is OK"); - return k->modifier_flags(); -JVM_END - - -// Inner class reflection /////////////////////////////////////////////////////////////////////////////// - JVM_ENTRY(jobjectArray, JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass)) JvmtiVMObjectAllocEventCollector oam; // ofClass is a reference to a java_lang_Class object. The mirror object diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 216616cefccc3..98b1b79681377 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -2717,19 +2717,10 @@ JvmtiEnv::GetSourceFileName(oop k_mirror, char** source_name_ptr) { // modifiers_ptr - pre-checked for null jvmtiError JvmtiEnv::GetClassModifiers(oop k_mirror, jint* modifiers_ptr) { - JavaThread* current_thread = JavaThread::current(); - jint result = 0; + jint result = java_lang_Class::modifiers(k_mirror); if (!java_lang_Class::is_primitive(k_mirror)) { - Klass* k = java_lang_Class::as_Klass(k_mirror); - NULL_CHECK(k, JVMTI_ERROR_INVALID_CLASS); - result = k->modifier_flags(); - // Reset the deleted ACC_SUPER bit (deleted in compute_modifier_flags()). - if (k->is_super()) { - result |= JVM_ACC_SUPER; - } - } else { - result = (JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC); + result |= JVM_ACC_SUPER; } *modifiers_ptr = result; diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 6613f30016109..ac6a6682beb69 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -262,7 +262,6 @@ nonstatic_field(Klass, _secondary_supers, Array*) \ nonstatic_field(Klass, _primary_supers[0], Klass*) \ nonstatic_field(Klass, _java_mirror, OopHandle) \ - nonstatic_field(Klass, _modifier_flags, u2) \ nonstatic_field(Klass, _super, Klass*) \ volatile_nonstatic_field(Klass, _subklass, Klass*) \ nonstatic_field(Klass, _layout_helper, jint) \ diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 4250910c84b24..68921601eca9d 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -236,11 +236,12 @@ private static void runtimeSetup() { * This constructor is not used and prevents the default constructor being * generated. */ - private Class(ClassLoader loader, Class arrayComponentType) { + private Class(ClassLoader loader, Class arrayComponentType, int mods) { // Initialize final field for classLoader. The initialization value of non-null // prevents future JIT optimizations from assuming this final field is null. classLoader = loader; componentType = arrayComponentType; + modifiers = mods; } /** @@ -1000,6 +1001,7 @@ public Module getModule() { private transient Object classData; // Set by VM private transient Object[] signers; // Read by VM, mutable + private final transient int modifiers; // Set by the VM // package-private Object getClassData() { @@ -1344,8 +1346,7 @@ private Class elementType() { * @jls 9.1.1 Interface Modifiers * @jvms 4.1 The {@code ClassFile} Structure */ - @IntrinsicCandidate - public native int getModifiers(); + public int getModifiers() { return modifiers; } /** * {@return an unmodifiable set of the {@linkplain AccessFlag access diff --git a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index 6b211284b4e86..95156dd19c2a1 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java +++ b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, 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 @@ -56,7 +56,7 @@ public class Reflection { fieldFilterMap = Map.of( Reflection.class, ALL_MEMBERS, AccessibleObject.class, ALL_MEMBERS, - Class.class, Set.of("classLoader", "classData"), + Class.class, Set.of("classLoader", "classData", "modifiers"), ClassLoader.class, ALL_MEMBERS, Constructor.class, ALL_MEMBERS, Field.class, ALL_MEMBERS, diff --git a/src/java.base/share/native/libjava/Class.c b/src/java.base/share/native/libjava/Class.c index ae8f372f57721..6e0ac7d230220 100644 --- a/src/java.base/share/native/libjava/Class.c +++ b/src/java.base/share/native/libjava/Class.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2025, 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 @@ -61,7 +61,6 @@ static JNINativeMethod methods[] = { {"isArray", "()Z", (void *)&JVM_IsArrayClass}, {"isHidden", "()Z", (void *)&JVM_IsHiddenClass}, {"isPrimitive", "()Z", (void *)&JVM_IsPrimitiveClass}, - {"getModifiers", "()I", (void *)&JVM_GetClassModifiers}, {"getDeclaredFields0","(Z)[" FLD, (void *)&JVM_GetClassDeclaredFields}, {"getDeclaredMethods0","(Z)[" MHD, (void *)&JVM_GetClassDeclaredMethods}, {"getDeclaredConstructors0","(Z)[" CTR, (void *)&JVM_GetClassDeclaredConstructors}, diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index 04f3f0b27879d..836378ae1f869 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -929,7 +929,7 @@ private static boolean isHiddenFromReflection(ResolvedJavaField f) { return true; } if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Class.class))) { - return f.getName().equals("classLoader") || f.getName().equals("classData"); + return f.getName().equals("classLoader") || f.getName().equals("classData") || f.getName().equals("modifiers"); } if (f.getDeclaringClass().equals(metaAccess.lookupJavaType(Lookup.class))) { return f.getName().equals("allowedModes") || f.getName().equals("lookupClass"); diff --git a/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java b/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java index c7c57d2371cb9..f101c87229ae6 100644 --- a/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java +++ b/test/jdk/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -147,7 +147,7 @@ public void testJavaLangClass() throws Exception { // non-public constructor Constructor ctor - = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class); + = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class, int.class); AccessibleObject[] ctors = { ctor }; try { diff --git a/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java b/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java index 22fcb2e01fa79..5fb7bb97bfccd 100644 --- a/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java +++ b/test/jdk/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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 @@ -193,7 +193,7 @@ public void testJavaLangClass() throws Exception { // non-public constructor Constructor ctor - = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class); + = Class.class.getDeclaredConstructor(ClassLoader.class, Class.class, int.class); AccessibleObject[] ctors = { ctor }; assertFalse(ctor.trySetAccessible()); diff --git a/test/jdk/jdk/internal/reflect/Reflection/Filtering.java b/test/jdk/jdk/internal/reflect/Reflection/Filtering.java index 97c7cf4c4928f..d714ff9d334e7 100644 --- a/test/jdk/jdk/internal/reflect/Reflection/Filtering.java +++ b/test/jdk/jdk/internal/reflect/Reflection/Filtering.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -23,7 +23,7 @@ /** * @test - * @bug 8210496 + * @bug 8210496 8346567 * @modules java.base/jdk.internal.reflect * @run testng Filtering * @summary Test that security sensitive fields that filtered by core reflection @@ -55,6 +55,7 @@ private Object[][] sensitiveFields() { { AccessibleObject.class, "override" }, { Class.class, "classLoader" }, { Class.class, "classData" }, + { Class.class, "modifiers" }, { ClassLoader.class, "parent" }, { Field.class, "clazz" }, { Field.class, "modifiers" }, diff --git a/test/micro/org/openjdk/bench/java/lang/reflect/Clazz.java b/test/micro/org/openjdk/bench/java/lang/reflect/Clazz.java index 46853ab698326..43ed83d338996 100644 --- a/test/micro/org/openjdk/bench/java/lang/reflect/Clazz.java +++ b/test/micro/org/openjdk/bench/java/lang/reflect/Clazz.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -33,8 +33,11 @@ import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; @BenchmarkMode(Mode.AverageTime) +@State(Scope.Benchmark) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) @@ -52,6 +55,41 @@ public Constructor getConstructor() throws NoSuchMethodException { return Clazz.class.getConstructor(); } + /** + * Get modifiers for this class through reflection + * + * @return + * @throws NoSuchMethodException + */ + @Benchmark + public int getModifiers() { + return Clazz.class.getModifiers(); + } + + Clazz[] clazzArray = new Clazz[1]; + @Benchmark + public int getAppArrayModifiers() { + return clazzArray.getClass().getModifiers(); + } + + static final Clazz[] clazzArrayFinal = new Clazz[1]; + @Benchmark + public int getAppArrayModifiersFinal() { + return clazzArrayFinal.getClass().getModifiers(); + } + + /** + * Get modifiers for an primitive array class through reflection + * + * @return + * @throws NoSuchMethodException + */ + @Benchmark + public int getArrayModifiers() { + return int[].class.getModifiers(); + } + + /** * Get constructor for the String class through reflection, forcing full * security check