Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/hotspot/share/oops/instanceKlass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3702,13 +3702,26 @@ const char* InstanceKlass::init_state_name() const {
return state_names[init_state()];
}

#if !defined(PRODUCT) || INCLUDE_JVMTI
void InstanceKlass::print_class_flags(outputStream* st) const {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incomplete. If the class is an inner class then additional access flags are possible (private, protected, static).
EDIT: Hmm jvm_constants.h does not recognise this either via JVM_RECOGNIZED_CLASS_MODIFIERS. Not sure how this should be handled.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also do we need to handle ACC_MODULE, or do we not actually create an instanceKlass for those?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On jdk side we never have Class for modules. These classfiles are exclusively handled by Java code in ModuleDescriptor I think?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have now changed it to use compute_modifier_flags() instead of access_flags() directly. With this, we get member-class modifiers printed. I expanded the test which shows that private/protected static gets printed. This matches the class' modifiers, which feels like the correct behavior.

ACC_MODULE is not needed here because it never becomes an InstanceKlass. It is rejected as a normal class during parsing.

AccessFlags flags = access_flags();
if (flags.is_public ()) st->print("public ");
if (flags.is_final ()) st->print("final ");
if (flags.is_interface ()) st->print("interface ");
if (flags.is_abstract ()) st->print("abstract ");
if (flags.is_annotation()) st->print("annotation ");
if (flags.is_enum ()) st->print("enum ");
if (flags.is_synthetic ()) st->print("synthetic ");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bit for SYNTHETIC, 0x1000, comes before ANNOTATION, 0x2000, and ENUM, 0x4000. That should be tracked in a separate issue though.

}
#endif // !defined(PRODUCT) || INCLUDE_JVMTI

void InstanceKlass::print_on(outputStream* st) const {
assert(is_klass(), "must be klass");
Klass::print_on(st);

st->print(BULLET"instance size: %d", size_helper()); st->cr();
st->print(BULLET"klass size: %d", size()); st->cr();
st->print(BULLET"access: "); access_flags().print_on(st); st->cr();
st->print(BULLET"access: "); print_class_flags(st); st->cr();
st->print(BULLET"flags: "); _misc_flags.print_on(st); st->cr();
st->print(BULLET"state: "); st->print_cr("%s", init_state_name());
st->print(BULLET"name: "); name()->print_value_on(st); st->cr();
Expand Down Expand Up @@ -3848,7 +3861,7 @@ void InstanceKlass::print_on(outputStream* st) const {

void InstanceKlass::print_value_on(outputStream* st) const {
assert(is_klass(), "must be klass");
if (Verbose || WizardMode) access_flags().print_on(st);
if (Verbose || WizardMode) print_class_flags(st);
name()->print_value_on(st);
}

Expand Down
5 changes: 5 additions & 0 deletions src/hotspot/share/oops/instanceKlass.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1169,6 +1169,11 @@ class InstanceKlass: public Klass {
// Printing
void print_on(outputStream* st) const override;
void print_value_on(outputStream* st) const override;
#if !defined(PRODUCT) || INCLUDE_JVMTI
void print_class_flags(outputStream* st) const;
#else
void print_class_flags(outputStream* st) const PRODUCT_RETURN;
#endif

void oop_print_value_on(oop obj, outputStream* st) override;

Expand Down
6 changes: 3 additions & 3 deletions src/hotspot/share/oops/klassVtable.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, 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
Expand Down Expand Up @@ -1066,7 +1066,7 @@ void klassVtable::dump_vtable() {
Method* m = unchecked_method_at(i);
if (m != nullptr) {
tty->print(" (%5d) ", i);
m->access_flags().print_on(tty);
m->print_access_flags(tty);
if (m->is_default_method()) {
tty->print("default ");
}
Expand Down Expand Up @@ -1421,7 +1421,7 @@ void klassItable::dump_itable() {
Method* m = ime->method();
if (m != nullptr) {
tty->print(" (%5d) ", i);
m->access_flags().print_on(tty);
m->print_access_flags(tty);
if (m->is_default_method()) {
tty->print("default ");
}
Expand Down
24 changes: 21 additions & 3 deletions src/hotspot/share/oops/method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2204,7 +2204,7 @@ void Method::print_on(outputStream* st) const {
st->print (" - method holder: "); method_holder()->print_value_on(st); st->cr();
st->print (" - constants: " PTR_FORMAT " ", p2i(constants()));
constants()->print_value_on(st); st->cr();
st->print (" - access: 0x%x ", access_flags().as_method_flags()); access_flags().print_on(st); st->cr();
st->print (" - access: 0x%x ", access_flags().as_method_flags()); print_access_flags(st); st->cr();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an existing inconsistency here in that we print the raw flags as "method flags" only but then we print them all. Your new code implicitly filters the flags by only printing the expected method flags.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as_method_flags() asserts that only recognized method modifiers are set, so these are not arbitrary raw flags. Previously, the generic printer could misinterpret overlapping bits, whereas the new method-specific printer prints them correctly. This looks like the right behavior to me.

st->print (" - flags: 0x%x ", _flags.as_int()); _flags.print_on(st); st->cr();
st->print (" - name: "); name()->print_value_on(st); st->cr();
st->print (" - signature: "); signature()->print_value_on(st); st->cr();
Expand Down Expand Up @@ -2278,8 +2278,8 @@ void Method::print_on(outputStream* st) const {
}
}

void Method::print_linkage_flags(outputStream* st) {
access_flags().print_on(st);
void Method::print_linkage_flags(outputStream* st) const {
print_access_flags(st);
if (is_default_method()) {
st->print("default ");
}
Expand All @@ -2289,6 +2289,24 @@ void Method::print_linkage_flags(outputStream* st) {
}
#endif //PRODUCT

#if !defined(PRODUCT) || INCLUDE_JVMTI
void Method::print_access_flags(outputStream* st) const {
AccessFlags flags = access_flags();
if (flags.is_public ()) st->print("public ");
if (flags.is_private ()) st->print("private ");
if (flags.is_protected ()) st->print("protected ");
if (flags.is_static ()) st->print("static ");
if (flags.is_final ()) st->print("final ");
if (flags.is_synchronized ()) st->print("synchronized ");
if (flags.is_bridge ()) st->print("bridge ");
if (flags.has_vararg ()) st->print("varargs ");
if (flags.is_native ()) st->print("native ");
if (flags.is_abstract ()) st->print("abstract ");
if (flags.is_strict_method()) st->print("strict ");
if (flags.is_synthetic ()) st->print("synthetic ");
}
#endif // !defined(PRODUCT) || INCLUDE_JVMTI

void Method::print_value_on(outputStream* st) const {
assert(is_method(), "must be method");
st->print("%s", internal_name());
Expand Down
7 changes: 6 additions & 1 deletion src/hotspot/share/oops/method.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -859,7 +859,12 @@ class Method : public Metadata {
void print_on(outputStream* st) const;
#endif
void print_value_on(outputStream* st) const;
void print_linkage_flags(outputStream* st) PRODUCT_RETURN;
#if !defined(PRODUCT) || INCLUDE_JVMTI
void print_access_flags(outputStream* st) const;
#else
void print_access_flags(outputStream* st) const PRODUCT_RETURN;
#endif
void print_linkage_flags(outputStream* st) const PRODUCT_RETURN;

const char* internal_name() const { return "{method}"; }

Expand Down
14 changes: 7 additions & 7 deletions src/hotspot/share/prims/jvmtiRedefineClasses.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2026, 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
Expand Down Expand Up @@ -4544,7 +4544,7 @@ void VM_RedefineClasses::dump_methods() {
LogStreamHandle(Trace, redefine, class, dump) log_stream;
Method* m = _old_methods->at(j);
log_stream.print("%4d (%5d) ", j, m->vtable_index());
m->access_flags().print_on(&log_stream);
m->print_access_flags(&log_stream);
log_stream.print(" -- ");
m->print_name(&log_stream);
log_stream.cr();
Expand All @@ -4554,7 +4554,7 @@ void VM_RedefineClasses::dump_methods() {
LogStreamHandle(Trace, redefine, class, dump) log_stream;
Method* m = _new_methods->at(j);
log_stream.print("%4d (%5d) ", j, m->vtable_index());
m->access_flags().print_on(&log_stream);
m->print_access_flags(&log_stream);
log_stream.print(" -- ");
m->print_name(&log_stream);
log_stream.cr();
Expand All @@ -4564,22 +4564,22 @@ void VM_RedefineClasses::dump_methods() {
LogStreamHandle(Trace, redefine, class, dump) log_stream;
Method* m = _matching_old_methods[j];
log_stream.print("%4d (%5d) ", j, m->vtable_index());
m->access_flags().print_on(&log_stream);
m->print_access_flags(&log_stream);
log_stream.print(" -- ");
m->print_name();
log_stream.cr();

m = _matching_new_methods[j];
log_stream.print(" (%5d) ", m->vtable_index());
m->access_flags().print_on(&log_stream);
m->print_access_flags(&log_stream);
log_stream.cr();
}
log_trace(redefine, class, dump)("_deleted_methods --");
for (j = 0; j < _deleted_methods_length; ++j) {
LogStreamHandle(Trace, redefine, class, dump) log_stream;
Method* m = _deleted_methods[j];
log_stream.print("%4d (%5d) ", j, m->vtable_index());
m->access_flags().print_on(&log_stream);
m->print_access_flags(&log_stream);
log_stream.print(" -- ");
m->print_name(&log_stream);
log_stream.cr();
Expand All @@ -4589,7 +4589,7 @@ void VM_RedefineClasses::dump_methods() {
LogStreamHandle(Trace, redefine, class, dump) log_stream;
Method* m = _added_methods[j];
log_stream.print("%4d (%5d) ", j, m->vtable_index());
m->access_flags().print_on(&log_stream);
m->print_access_flags(&log_stream);
log_stream.print(" -- ");
m->print_name(&log_stream);
log_stream.cr();
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/prims/methodHandles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) {
ls.print_cr("memberName: invokeinterface method_holder::method: %s, itableindex: %d, access_flags:",
Method::name_and_sig_as_C_string(m->method_holder(), m->name(), m->signature()),
vmindex);
m->access_flags().print_on(&ls);
m->print_access_flags(&ls);
if (!m->is_abstract()) {
if (!m->is_private()) {
ls.print("default");
Expand Down Expand Up @@ -314,7 +314,7 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) {
ls.print_cr("memberName: invokevirtual method_holder::method: %s, receiver: %s, vtableindex: %d, access_flags:",
Method::name_and_sig_as_C_string(m->method_holder(), m->name(), m->signature()),
m_klass->internal_name(), vmindex);
m->access_flags().print_on(&ls);
m->print_access_flags(&ls);
if (m->is_default_method()) {
ls.print("default");
}
Expand Down
19 changes: 17 additions & 2 deletions src/hotspot/share/runtime/fieldDescriptor.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, 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
Expand Down Expand Up @@ -108,8 +108,23 @@ void fieldDescriptor::reinitialize(InstanceKlass* ik, const FieldInfo& fieldinfo
guarantee(_fieldinfo.name_index() != 0 && _fieldinfo.signature_index() != 0, "bad constant pool index for fieldDescriptor");
}

#if !defined(PRODUCT) || INCLUDE_JVMTI
void fieldDescriptor::print_access_flags(outputStream* st) const {
AccessFlags flags = access_flags();
if (flags.is_public ()) st->print("public ");
if (flags.is_private ()) st->print("private ");
if (flags.is_protected()) st->print("protected ");
if (flags.is_static ()) st->print("static ");
if (flags.is_final ()) st->print("final ");
if (flags.is_volatile ()) st->print("volatile ");
if (flags.is_transient()) st->print("transient ");
if (flags.is_enum ()) st->print("enum ");
if (flags.is_synthetic()) st->print("synthetic ");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same SYNTHETIC remark here.

}
#endif // !defined(PRODUCT) || INCLUDE_JVMTI

void fieldDescriptor::print_on(outputStream* st) const {
access_flags().print_on(st);
print_access_flags(st);
if (field_flags().is_injected()) st->print("injected ");
name()->print_value_on(st);
st->print(" ");
Expand Down
7 changes: 6 additions & 1 deletion src/hotspot/share/runtime/fieldDescriptor.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, 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
Expand Down Expand Up @@ -111,6 +111,11 @@ class fieldDescriptor {
void print() const;
void print_on(outputStream* st) const;
void print_on_for(outputStream* st, oop obj);
#if !defined(PRODUCT) || INCLUDE_JVMTI
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new !defined(PRODUCT) seems to be only for the gtest. I wonder if gtest can run the test for print_access_flags based on INCLUDE_JVMTI flag instead; the macro condition tweak seems weird.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am surprised that we only ever print access flags in relation to JVMTI - I would have expected logging or crash reporting to do so. In any case I also find the !PRODUCT a little jarring. Given we always have JVMTI it makes no different to our binaries.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After some thought, I have removed all the #if guards on the printers. To me, these are now ordinary printing utilities belonging to either Method, InstanceKlass, or fieldDescriptor. They are not directly tied to JVMTI, so should not be guarded by it. Let me know if you agree.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is fine with me.

void print_access_flags(outputStream* st) const;
#else
void print_access_flags(outputStream* st) const PRODUCT_RETURN;
#endif
};

#endif // SHARE_RUNTIME_FIELDDESCRIPTOR_HPP
23 changes: 1 addition & 22 deletions src/hotspot/share/utilities/accessFlags.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, 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
Expand All @@ -22,29 +22,8 @@
*
*/

#include "oops/oop.inline.hpp"
#include "runtime/atomicAccess.hpp"
#include "utilities/accessFlags.hpp"

#if !defined(PRODUCT) || INCLUDE_JVMTI

void AccessFlags::print_on(outputStream* st) const {
if (is_public ()) st->print("public " );
if (is_private ()) st->print("private " );
if (is_protected ()) st->print("protected " );
if (is_static ()) st->print("static " );
if (is_final ()) st->print("final " );
if (is_synchronized()) st->print("synchronized ");
if (is_volatile ()) st->print("volatile " );
if (is_transient ()) st->print("transient " );
if (is_native ()) st->print("native " );
if (is_interface ()) st->print("interface " );
if (is_abstract ()) st->print("abstract " );
if (is_synthetic ()) st->print("synthetic " );
}

#endif // !PRODUCT || INCLUDE_JVMTI

void accessFlags_init() {
assert(sizeof(AccessFlags) == sizeof(u2), "just checking size of flags");
}
14 changes: 6 additions & 8 deletions src/hotspot/share/utilities/accessFlags.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2026, 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
Expand Down Expand Up @@ -53,10 +53,15 @@ class AccessFlags {
bool is_synchronized() const { return (_flags & JVM_ACC_SYNCHRONIZED) != 0; }
bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; }
bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; }
bool is_bridge () const { return (_flags & JVM_ACC_BRIDGE ) != 0; }
bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; }
bool has_vararg () const { return (_flags & JVM_ACC_VARARGS ) != 0; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend is_varargs, this flag is not enforced by the VM so technically users can create class files that declare varargs methods without a trailing array argument.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed it to is_varargs. I originally picked has_varargs because that is the name on the valhalla branch, but I am fine with this too.

bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; }
bool is_enum () const { return (_flags & JVM_ACC_ENUM ) != 0; }
bool is_annotation () const { return (_flags & JVM_ACC_ANNOTATION ) != 0; }
bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; }
bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; }
bool is_strict_method() const { return (_flags & JVM_ACC_STRICT ) != 0; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If "strict method" sounds too weird, we can call this "strictfp" following the original Java language modifier's name.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be short-lived either way as valhalla gets rid of the legacy strictfp notion for methods anyway.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to is_strictfp instead.


// Attribute flags
bool is_synthetic () const { return (_flags & JVM_ACC_SYNTHETIC ) != 0; }
Expand Down Expand Up @@ -92,13 +97,6 @@ class AccessFlags {
assert((_flags & JVM_RECOGNIZED_CLASS_MODIFIERS) == _flags, "only recognized flags");
return _flags;
}

// Printing/debugging
#if INCLUDE_JVMTI
void print_on(outputStream* st) const;
#else
void print_on(outputStream* st) const PRODUCT_RETURN;
#endif
};

inline AccessFlags accessFlags_from(u2 flags) {
Expand Down
Loading