diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index a3d295d2562..d450d12fd51 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -109,7 +109,8 @@ // and make it simpler to print from the debugger. struct java_nmethod_stats_struct { int nmethod_count; - int total_size; + int total_nm_size; + int total_immut_size; int relocation_size; int consts_size; int insts_size; @@ -124,7 +125,8 @@ struct java_nmethod_stats_struct { void note_nmethod(nmethod* nm) { nmethod_count += 1; - total_size += nm->size(); + total_nm_size += nm->size(); + total_immut_size += nm->immutable_data_size(); relocation_size += nm->relocation_size(); consts_size += nm->consts_size(); insts_size += nm->insts_size(); @@ -140,7 +142,14 @@ struct java_nmethod_stats_struct { void print_nmethod_stats(const char* name) { if (nmethod_count == 0) return; tty->print_cr("Statistics for %d bytecoded nmethods for %s:", nmethod_count, name); - if (total_size != 0) tty->print_cr(" total in heap = %d", total_size); + int total_size = total_nm_size + total_immut_size; + if (ReduceNMethodSize) { + tty->print_cr(" total size = %u (100%%)", total_size); + tty->print_cr(" in CodeCache = %u (%f%%)", total_nm_size, (total_nm_size * 100.0f)/total_size); + } else { + assert(total_nm_size == total_size, "no immutable data"); + if (total_nm_size != 0) tty->print_cr(" total in heap = %d", total_size); + } if (nmethod_count != 0) tty->print_cr(" header = " SIZE_FORMAT, nmethod_count * sizeof(nmethod)); if (relocation_size != 0) tty->print_cr(" relocation = %d", relocation_size); if (consts_size != 0) tty->print_cr(" constants = %d", consts_size); @@ -493,17 +502,36 @@ nmethod* nmethod::new_nmethod(const methodHandle& method, code_buffer->finalize_oop_references(method); // create nmethod nmethod* nm = NULL; - { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - int nmethod_size = - CodeBlob::allocation_size(code_buffer, sizeof(nmethod)) + int nmethod_size = 0; + int immutable_data_size = 0; + if (ReduceNMethodSize) { + nmethod_size = CodeBlob::allocation_size(code_buffer, sizeof(nmethod)); + immutable_data_size = adjust_pcs_size(debug_info->pcs_size()) + + align_up((int)dependencies->size_in_bytes(), oopSize) + + align_up(handler_table->size_in_bytes() , oopSize) + + align_up(nul_chk_table->size_in_bytes() , oopSize) + + align_up(debug_info->data_size() , oopSize); + } else { + nmethod_size = CodeBlob::allocation_size(code_buffer, sizeof(nmethod)) + adjust_pcs_size(debug_info->pcs_size()) + align_up((int)dependencies->size_in_bytes(), oopSize) + align_up(handler_table->size_in_bytes() , oopSize) + align_up(nul_chk_table->size_in_bytes() , oopSize) + align_up(debug_info->data_size() , oopSize); - + } + // First, allocate space for immutable data in C heap. + address immutable_data = NULL; + if (immutable_data_size > 0) { + immutable_data = (address)os::malloc(immutable_data_size, mtCode); + if (immutable_data == NULL) { + vm_exit_out_of_memory(immutable_data_size, OOM_MALLOC_ERROR, "nmethod: no space for immutable data"); + return NULL; + } + } + { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); nm = new (nmethod_size, comp_level) - nmethod(method(), compiler->type(), nmethod_size, compile_id, entry_bci, offsets, + nmethod(method(), compiler->type(), nmethod_size, immutable_data_size, + compile_id, entry_bci, immutable_data, offsets, orig_pc_offset, debug_info, dependencies, code_buffer, frame_size, oop_maps, handler_table, @@ -565,6 +593,7 @@ nmethod::nmethod( OopMapSet* oop_maps ) : CompiledMethod(method, "native nmethod", type, nmethod_size, sizeof(nmethod), code_buffer, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false), ZGC_ONLY_ARG(_is_unloading_state(0)) + _immutable_data_size(0), _native_receiver_sp_offset(basic_lock_owner_sp_offset), _native_basic_lock_sp_offset(basic_lock_sp_offset) { @@ -602,6 +631,7 @@ nmethod::nmethod( _pc_desc_container.reset_to(NULL); _hotness_counter = NMethodSweeper::hotness_counter_reset_val(); + _immutable_data = data_end(); _scopes_data_begin = (address) this + scopes_data_offset; _deopt_handler_begin = (address) this + deoptimize_offset; _deopt_mh_handler_begin = (address) this + deoptimize_mh_offset; @@ -654,8 +684,10 @@ nmethod::nmethod( Method* method, CompilerType type, int nmethod_size, + int immutable_data_size, int compile_id, int entry_bci, + address immutable_data, CodeOffsets* offsets, int orig_pc_offset, DebugInformationRecorder* debug_info, @@ -674,6 +706,7 @@ nmethod::nmethod( ) : CompiledMethod(method, "nmethod", type, nmethod_size, sizeof(nmethod), code_buffer, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false), ZGC_ONLY_ARG(_is_unloading_state(0)) + _immutable_data_size(immutable_data_size), _native_receiver_sp_offset(in_ByteSize(-1)), _native_basic_lock_sp_offset(in_ByteSize(-1)) { @@ -746,21 +779,32 @@ nmethod::nmethod( _unwind_handler_offset = -1; } + bool use_immutable_data = immutable_data_size > 0; + if (immutable_data_size > 0) { + assert(ReduceNMethodSize && immutable_data != NULL, "required"); + _immutable_data = immutable_data; + } else { + // We need unique not null address + _immutable_data = data_end(); + } _oops_offset = data_offset(); _metadata_offset = _oops_offset + align_up(code_buffer->total_oop_size(), oopSize); - int scopes_data_offset = _metadata_offset + align_up(code_buffer->total_metadata_size(), wordSize); + int scopes_data_offset = use_immutable_data ? 0 // start of immutable data + : _metadata_offset + align_up(code_buffer->total_metadata_size(), wordSize); _scopes_pcs_offset = scopes_data_offset + align_up(debug_info->data_size (), oopSize); _dependencies_offset = _scopes_pcs_offset + adjust_pcs_size(debug_info->pcs_size()); _handler_table_offset = _dependencies_offset + align_up((int)dependencies->size_in_bytes (), oopSize); _nul_chk_table_offset = _handler_table_offset + align_up(handler_table->size_in_bytes(), oopSize); - _nmethod_end_offset = _nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize); + _nmethod_end_offset = use_immutable_data ? _data_end - (address)this + : _nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize); _entry_point = code_begin() + offsets->value(CodeOffsets::Entry); _verified_entry_point = code_begin() + offsets->value(CodeOffsets::Verified_Entry); _osr_entry_point = code_begin() + offsets->value(CodeOffsets::OSR_Entry); _exception_cache = NULL; - _scopes_data_begin = (address) this + scopes_data_offset; + _scopes_data_begin = use_immutable_data ? _immutable_data + : (address) this + scopes_data_offset; _pc_desc_container.reset_to(scopes_pcs_begin()); @@ -2377,6 +2421,10 @@ void nmethod::print() const { p2i(metadata_begin()), p2i(metadata_end()), metadata_size()); + if (immutable_data_size() > 0) tty->print_cr(" immutable data [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", + p2i(immutable_data_begin()), + p2i(immutable_data_end()), + immutable_data_size()); if (scopes_data_size () > 0) tty->print_cr(" scopes data [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d", p2i(scopes_data_begin()), p2i(scopes_data_end()), diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index db23ef3689e..a764160f9bb 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -58,9 +58,12 @@ class nmethod : public CompiledMethod { friend class NMethodSweeper; friend class CodeCache; // scavengable oops private: + // nmethod's read-only data + address _immutable_data; // Shared fields for all nmethod's int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method + int _immutable_data_size; #if INCLUDE_JVMCI // A weak reference to an InstalledCode object associated with @@ -101,11 +104,13 @@ class nmethod : public CompiledMethod { int _stub_offset; int _oops_offset; // offset to where embedded oop table begins (inside data) int _metadata_offset; // embedded meta data table + // Offset in immutable data section int _scopes_data_offset; int _scopes_pcs_offset; int _dependencies_offset; int _handler_table_offset; int _nul_chk_table_offset; + int _nmethod_end_offset; int code_offset() const { return (address) code_begin() - header_begin(); } @@ -197,8 +202,10 @@ class nmethod : public CompiledMethod { nmethod(Method* method, CompilerType type, int nmethod_size, + int immutable_data_size, int compile_id, int entry_bci, + address immutable_data, CodeOffsets* offsets, int orig_pc_offset, DebugInformationRecorder *recorder, @@ -220,6 +227,7 @@ class nmethod : public CompiledMethod { void* operator new(size_t size, int nmethod_size, int comp_level) throw(); const char* reloc_string_for(u_char* begin, u_char* end); + // Returns true if this thread changed the state of the nmethod or // false if another thread performed the transition. bool make_not_entrant_or_zombie(int state); @@ -281,23 +289,89 @@ class nmethod : public CompiledMethod { address stub_end () const { return header_begin() + _oops_offset ; } address exception_begin () const { return header_begin() + _exception_offset ; } address unwind_handler_begin () const { return _unwind_handler_offset != -1 ? (header_begin() + _unwind_handler_offset) : NULL; } + // mutable data oop* oops_begin () const { return (oop*) (header_begin() + _oops_offset) ; } oop* oops_end () const { return (oop*) (header_begin() + _metadata_offset) ; } Metadata** metadata_begin () const { return (Metadata**) (header_begin() + _metadata_offset) ; } - Metadata** metadata_end () const { return (Metadata**) _scopes_data_begin; } - - address scopes_data_end () const { return header_begin() + _scopes_pcs_offset ; } - PcDesc* scopes_pcs_begin () const { return (PcDesc*)(header_begin() + _scopes_pcs_offset ); } - PcDesc* scopes_pcs_end () const { return (PcDesc*)(header_begin() + _dependencies_offset) ; } - address dependencies_begin () const { return header_begin() + _dependencies_offset ; } - address dependencies_end () const { return header_begin() + _handler_table_offset ; } - address handler_table_begin () const { return header_begin() + _handler_table_offset ; } - address handler_table_end () const { return header_begin() + _nul_chk_table_offset ; } - address nul_chk_table_begin () const { return header_begin() + _nul_chk_table_offset ; } - address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; } + Metadata** metadata_end () const { + if (_immutable_data_size > 0) { + return (Metadata**) data_end(); + } else { + return (Metadata**) _scopes_data_begin; + } + } + + // immutable data + address immutable_data_begin() const { return _immutable_data; } + address immutable_data_end () const { return _immutable_data + _immutable_data_size; } + + address scopes_data_end() const { + if (_immutable_data_size > 0) { + return immutable_data_begin() + _scopes_pcs_offset; + } else { + return header_begin() + _scopes_pcs_offset; + } + } + PcDesc* scopes_pcs_begin() const { + if (_immutable_data_size > 0) { + return (PcDesc *) (immutable_data_begin() + _scopes_pcs_offset); + } else { + return (PcDesc *) (header_begin() + _scopes_pcs_offset); + } + } + PcDesc* scopes_pcs_end() const { + if (_immutable_data_size > 0) { + return (PcDesc *) (immutable_data_begin() + _dependencies_offset); + } else { + return (PcDesc *) (header_begin() + _dependencies_offset); + } + } + address dependencies_begin() const { + if (_immutable_data_size > 0) { + return immutable_data_begin() + _dependencies_offset; + } else { + return header_begin() + _dependencies_offset; + } + } + address dependencies_end() const { + if (_immutable_data_size > 0) { + return immutable_data_begin() + _handler_table_offset; + } else { + return header_begin() + _handler_table_offset; + } + } + address handler_table_begin() const { + if (_immutable_data_size > 0) { + return immutable_data_begin() + _handler_table_offset; + } else { + return header_begin() + _handler_table_offset; + } + } + address handler_table_end() const { + if (_immutable_data_size > 0) { + return immutable_data_begin() + _nul_chk_table_offset; + } else { + return header_begin() + _nul_chk_table_offset; + } + } + address nul_chk_table_begin () const { + if (_immutable_data_size > 0) { + return immutable_data_begin() + _nul_chk_table_offset; + } else { + return header_begin() + _nul_chk_table_offset; + } + } + address nul_chk_table_end () const { + if (_immutable_data_size > 0) { + return immutable_data_end(); + } else { + return header_begin() + _nmethod_end_offset; + } + } // Sizes + int immutable_data_size() const { return _immutable_data_size; } int oops_size () const { return (address) oops_end () - (address) oops_begin (); } int metadata_size () const { return (address) metadata_end () - (address) metadata_begin (); } int dependencies_size () const { return dependencies_end () - dependencies_begin (); } diff --git a/src/hotspot/share/runtime/globals_ext.hpp b/src/hotspot/share/runtime/globals_ext.hpp index 642e932dfac..e36fb6a27f3 100644 --- a/src/hotspot/share/runtime/globals_ext.hpp +++ b/src/hotspot/share/runtime/globals_ext.hpp @@ -90,6 +90,9 @@ product(bool, G1BarrierSimple, false, \ "Use simple G1 post barrier") \ \ + product(bool, ReduceNMethodSize, false, \ + "Move immutable data of nmethod out of code cache") \ + \ //add new AJDK specific flags here diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index d788805ecbf..463dad9fdb2 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -729,6 +729,8 @@ typedef PaddedEnd PaddedObjectMonitor; nonstatic_field(nmethod, _entry_point, address) \ nonstatic_field(nmethod, _verified_entry_point, address) \ nonstatic_field(nmethod, _osr_entry_point, address) \ + nonstatic_field(nmethod, _immutable_data, address) \ + nonstatic_field(nmethod, _immutable_data_size, int) \ volatile_nonstatic_field(nmethod, _lock_count, jint) \ volatile_nonstatic_field(nmethod, _stack_traversal_mark, long) \ nonstatic_field(nmethod, _compile_id, int) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index a9522d78535..fa87d4fcb43 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -38,6 +38,8 @@ public class NMethod extends CompiledMethod { private static CIntegerField entryBCIField; /** To support simple linked-list chaining of nmethods */ private static AddressField osrLinkField; + private static AddressField immutableDataField; + private static CIntegerField immutableDataSizeField; private static AddressField scavengeRootLinkField; private static JByteField scavengeRootStateField; @@ -88,6 +90,8 @@ private static void initialize(TypeDataBase db) { entryBCIField = type.getCIntegerField("_entry_bci"); osrLinkField = type.getAddressField("_osr_link"); + immutableDataField = type.getAddressField("_immutable_data"); + immutableDataSizeField = type.getCIntegerField("_immutable_data_size"); scavengeRootLinkField = type.getAddressField("_scavenge_root_link"); scavengeRootStateField = type.getJByteField("_scavenge_root_state"); @@ -126,6 +130,8 @@ public Address getAddress() { public boolean isOSRMethod() { return getEntryBCI() != VM.getVM().getInvocationEntryBCI(); } /** Boundaries for different parts */ + public Address immutableDataBegin() { return immutableDataField.getValue(addr); } + public Address immutableDataEnd() { return immutableDataBegin().addOffsetTo(getImmutableDataSize()); } public Address constantsBegin() { return contentBegin(); } public Address constantsEnd() { return getEntryPoint(); } public Address instsBegin() { return codeBegin(); } @@ -136,16 +142,76 @@ public Address getAddress() { public Address oopsBegin() { return headerBegin().addOffsetTo(getOopsOffset()); } public Address oopsEnd() { return headerBegin().addOffsetTo(getMetadataOffset()); } public Address metadataBegin() { return headerBegin().addOffsetTo(getMetadataOffset()); } - public Address metadataEnd() { return scopesDataBegin(); } - public Address scopesDataEnd() { return headerBegin().addOffsetTo(getScopesPCsOffset()); } - public Address scopesPCsBegin() { return headerBegin().addOffsetTo(getScopesPCsOffset()); } - public Address scopesPCsEnd() { return headerBegin().addOffsetTo(getDependenciesOffset()); } - public Address dependenciesBegin() { return headerBegin().addOffsetTo(getDependenciesOffset()); } - public Address dependenciesEnd() { return headerBegin().addOffsetTo(getHandlerTableOffset()); } - public Address handlerTableBegin() { return headerBegin().addOffsetTo(getHandlerTableOffset()); } - public Address handlerTableEnd() { return headerBegin().addOffsetTo(getNulChkTableOffset()); } - public Address nulChkTableBegin() { return headerBegin().addOffsetTo(getNulChkTableOffset()); } - public Address nulChkTableEnd() { return headerBegin().addOffsetTo(getNMethodEndOffset()); } + public Address metadataEnd() { + if (getImmutableDataSize() > 0) { + return dataEnd(); + } else { + return scopesDataBegin(); + } + } + public Address scopesDataEnd() { + if (getImmutableDataSize() > 0) { + return immutableDataBegin().addOffsetTo(getScopesPCsOffset()); + } else { + return headerBegin().addOffsetTo(getScopesPCsOffset()); + } + } + public Address scopesPCsBegin() { + if (getImmutableDataSize() > 0) { + return immutableDataBegin().addOffsetTo(getScopesPCsOffset()); + } else { + return headerBegin().addOffsetTo(getScopesPCsOffset()); + } + } + public Address scopesPCsEnd() { + if (getImmutableDataSize() > 0) { + return immutableDataBegin().addOffsetTo(getDependenciesOffset()); + } else { + return headerBegin().addOffsetTo(getDependenciesOffset()); + } + } + public Address dependenciesBegin() { + if (getImmutableDataSize() > 0) { + return immutableDataBegin().addOffsetTo(getDependenciesOffset()); + } else { + return headerBegin().addOffsetTo(getDependenciesOffset()); + } + } + public Address dependenciesEnd() { + if (getImmutableDataSize() > 0) { + return immutableDataBegin().addOffsetTo(getHandlerTableOffset()); + } else { + return headerBegin().addOffsetTo(getHandlerTableOffset()); + } + } + public Address handlerTableBegin() { + if (getImmutableDataSize() > 0) { + return immutableDataBegin().addOffsetTo(getHandlerTableOffset()); + } else { + return headerBegin().addOffsetTo(getHandlerTableOffset()); + } + } + public Address handlerTableEnd() { + if (getImmutableDataSize() > 0) { + return immutableDataBegin().addOffsetTo(getNulChkTableOffset()); + } else { + return headerBegin().addOffsetTo(getNulChkTableOffset()); + } + } + public Address nulChkTableBegin() { + if (getImmutableDataSize() > 0) { + return immutableDataBegin().addOffsetTo(getNulChkTableOffset()); + } else { + return headerBegin().addOffsetTo(getNulChkTableOffset()); + } + } + public Address nulChkTableEnd() { + if (getImmutableDataSize() > 0) { + return immutableDataBegin().addOffsetTo(getImmutableDataSize()); + } else { + return headerBegin().addOffsetTo(getNMethodEndOffset()); + } + } public int constantsSize() { return (int) constantsEnd() .minus(constantsBegin()); } public int instsSize() { return (int) instsEnd() .minus(instsBegin()); } @@ -160,7 +226,13 @@ public Address getAddress() { public int origPCOffset() { return (int) origPCOffsetField.getValue(addr); } public int totalSize() { - return + if (getImmutableDataSize() > 0) { + return + constantsSize() + + instsSize() + + stubSize(); + } else { + return constantsSize() + instsSize() + stubSize() + @@ -169,6 +241,7 @@ public int totalSize() { dependenciesSize() + handlerTableSize() + nulChkTableSize(); + } } public boolean constantsContains (Address addr) { return constantsBegin() .lessThanOrEqual(addr) && constantsEnd() .greaterThan(addr); } @@ -536,4 +609,5 @@ public void dumpReplayData(PrintStream out) { private int getNulChkTableOffset() { return (int) nulChkTableOffsetField .getValue(addr); } private int getNMethodEndOffset() { return (int) nmethodEndOffsetField .getValue(addr); } private int getCompLevel() { return (int) compLevelField .getValue(addr); } + private int getImmutableDataSize() { return (int) immutableDataSizeField .getValue(addr); } }