mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8263002: Remove CDS MiscCode region
Reviewed-by: coleenp, dholmes
This commit is contained in:
parent
67ea3bd6a4
commit
d8a9c3ca92
@ -240,15 +240,6 @@ bool SharedRuntime::is_wide_vector(int size) {
|
||||
return size > 8;
|
||||
}
|
||||
|
||||
size_t SharedRuntime::trampoline_size() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) {
|
||||
__ mov(rscratch1, destination);
|
||||
__ br(rscratch1);
|
||||
}
|
||||
|
||||
// The java_calling_convention describes stack locations as ideal slots on
|
||||
// a frame with no abi restrictions. Since we must observe abi restrictions
|
||||
// (like the placement of the register window) the slots must be biased by
|
||||
|
||||
@ -251,16 +251,6 @@ bool SharedRuntime::is_wide_vector(int size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t SharedRuntime::trampoline_size() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) {
|
||||
InlinedAddress dest(destination);
|
||||
__ indirect_jump(dest, Rtemp);
|
||||
__ bind_literal(dest);
|
||||
}
|
||||
|
||||
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||
VMRegPair *regs,
|
||||
VMRegPair *regs2,
|
||||
|
||||
@ -564,17 +564,6 @@ bool SharedRuntime::is_wide_vector(int size) {
|
||||
return size > 8;
|
||||
}
|
||||
|
||||
size_t SharedRuntime::trampoline_size() {
|
||||
return Assembler::load_const_size + 8;
|
||||
}
|
||||
|
||||
void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) {
|
||||
Register Rtemp = R12;
|
||||
__ load_const(Rtemp, destination);
|
||||
__ mtctr(Rtemp);
|
||||
__ bctr();
|
||||
}
|
||||
|
||||
static int reg2slot(VMReg r) {
|
||||
return r->reg2stack() + SharedRuntime::out_preserve_stack_slots();
|
||||
}
|
||||
|
||||
@ -556,16 +556,6 @@ void RegisterSaver::restore_result_registers(MacroAssembler* masm) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t SharedRuntime::trampoline_size() {
|
||||
return MacroAssembler::load_const_size() + 2;
|
||||
}
|
||||
|
||||
void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) {
|
||||
// Think about using pc-relative branch.
|
||||
__ load_const(Z_R1_scratch, destination);
|
||||
__ z_br(Z_R1_scratch);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
void SharedRuntime::save_native_result(MacroAssembler * masm,
|
||||
BasicType ret_type,
|
||||
|
||||
@ -371,14 +371,6 @@ bool SharedRuntime::is_wide_vector(int size) {
|
||||
return size > 16;
|
||||
}
|
||||
|
||||
size_t SharedRuntime::trampoline_size() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) {
|
||||
__ jump(RuntimeAddress(destination));
|
||||
}
|
||||
|
||||
// The java_calling_convention describes stack locations as ideal slots on
|
||||
// a frame with no abi restrictions. Since we must observe abi restrictions
|
||||
// (like the placement of the register window) the slots must be biased by
|
||||
|
||||
@ -423,14 +423,6 @@ bool SharedRuntime::is_wide_vector(int size) {
|
||||
return size > 16;
|
||||
}
|
||||
|
||||
size_t SharedRuntime::trampoline_size() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) {
|
||||
__ jump(RuntimeAddress(destination));
|
||||
}
|
||||
|
||||
// The java_calling_convention describes stack locations as ideal slots on
|
||||
// a frame with no abi restrictions. Since we must observe abi restrictions
|
||||
// (like the placement of the register window) the slots must be biased by
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -119,16 +119,6 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
|
||||
return generate_empty_runtime_stub("resolve_blob");
|
||||
}
|
||||
|
||||
size_t SharedRuntime::trampoline_size() {
|
||||
ShouldNotCallThis();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SharedRuntime::generate_trampoline(MacroAssembler *masm, address destination) {
|
||||
ShouldNotCallThis();
|
||||
return;
|
||||
}
|
||||
|
||||
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||
VMRegPair *regs,
|
||||
VMRegPair *regs2,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2021, 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
|
||||
@ -67,12 +67,6 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MetaspaceShared::is_in_trampoline_frame(addr)) {
|
||||
// In the middle of a trampoline call. Bail out for safety.
|
||||
// This happens rarely so shouldn't affect profiling.
|
||||
return false;
|
||||
}
|
||||
|
||||
frame ret_frame(ret_sp, ret_fp, addr);
|
||||
if (!ret_frame.safe_for_sender(this)) {
|
||||
#if COMPILER2_OR_JVMCI
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -68,12 +68,6 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MetaspaceShared::is_in_trampoline_frame(addr)) {
|
||||
// In the middle of a trampoline call. Bail out for safety.
|
||||
// This happens rarely so shouldn't affect profiling.
|
||||
return false;
|
||||
}
|
||||
|
||||
frame ret_frame(ret_sp, ret_fp, addr);
|
||||
if (!ret_frame.safe_for_sender(this)) {
|
||||
#ifdef COMPILER2
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2021, 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
|
||||
@ -101,12 +101,6 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MetaspaceShared::is_in_trampoline_frame(addr)) {
|
||||
// In the middle of a trampoline call. Bail out for safety.
|
||||
// This happens rarely so shouldn't affect profiling.
|
||||
return false;
|
||||
}
|
||||
|
||||
frame ret_frame(ret_sp, ret_fp, addr);
|
||||
if (!ret_frame.safe_for_sender(this)) {
|
||||
#ifdef COMPILER2
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2021, 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
|
||||
@ -68,12 +68,6 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MetaspaceShared::is_in_trampoline_frame(addr)) {
|
||||
// In the middle of a trampoline call. Bail out for safety.
|
||||
// This happens rarely so shouldn't affect profiling.
|
||||
return false;
|
||||
}
|
||||
|
||||
frame ret_frame(ret_sp, ret_fp, addr);
|
||||
if (!ret_frame.safe_for_sender(this)) {
|
||||
#if COMPILER2_OR_JVMCI
|
||||
|
||||
@ -69,12 +69,6 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MetaspaceShared::is_in_trampoline_frame(ret_frame.pc())) {
|
||||
// In the middle of a trampoline call. Bail out for safety.
|
||||
// This happens rarely so shouldn't affect profiling.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ret_frame.safe_for_sender(jt)) {
|
||||
#if COMPILER2_OR_JVMCI
|
||||
// C2 and JVMCI use ebp as a general register see if NULL fp helps
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2021, 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
|
||||
@ -64,12 +64,6 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MetaspaceShared::is_in_trampoline_frame(ret_frame.pc())) {
|
||||
// In the middle of a trampoline call. Bail out for safety.
|
||||
// This happens rarely so shouldn't affect profiling.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ret_frame.safe_for_sender(this)) {
|
||||
#if COMPILER2_OR_JVMCI
|
||||
// C2 and JVMCI use ebp as a general register see if NULL fp helps
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2021, 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,10 +33,10 @@
|
||||
//
|
||||
// Also, this is a C header file. Do not use C++ here.
|
||||
|
||||
#define NUM_CDS_REGIONS 8 // this must be the same as MetaspaceShared::n_regions
|
||||
#define NUM_CDS_REGIONS 7 // this must be the same as MetaspaceShared::n_regions
|
||||
#define CDS_ARCHIVE_MAGIC 0xf00baba2
|
||||
#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
|
||||
#define CURRENT_CDS_ARCHIVE_VERSION 10
|
||||
#define CURRENT_CDS_ARCHIVE_VERSION 11
|
||||
#define INVALID_CDS_ARCHIVE_VERSION -1
|
||||
|
||||
struct CDSFileMapRegion {
|
||||
@ -44,7 +44,7 @@ struct CDSFileMapRegion {
|
||||
int _read_only; // read only region?
|
||||
int _allow_exec; // executable code in this region?
|
||||
int _is_heap_region; // Used by SA and debug build.
|
||||
int _is_bitmap_region; // Relocation bitmap for RO/RW/MC/MD regions (used by SA and debug build).
|
||||
int _is_bitmap_region; // Relocation bitmap for RO/RW regions (used by SA and debug build).
|
||||
int _mapped_from_file; // Is this region mapped from a file?
|
||||
// If false, this region was initialized using os::read().
|
||||
size_t _file_offset; // Data for this region starts at this offset in the archive file.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2021, 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
|
||||
@ -92,7 +92,6 @@ address AbstractInterpreter::_native_entry_begin = NU
|
||||
address AbstractInterpreter::_native_entry_end = NULL;
|
||||
address AbstractInterpreter::_slow_signature_handler;
|
||||
address AbstractInterpreter::_entry_table [AbstractInterpreter::number_of_method_entries];
|
||||
address AbstractInterpreter::_cds_entry_table [AbstractInterpreter::number_of_method_entries];
|
||||
address AbstractInterpreter::_native_abi_to_tosca [AbstractInterpreter::number_of_result_handlers];
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
@ -200,49 +199,11 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(const methodHan
|
||||
return zerolocals;
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
|
||||
// For a shared Method m, to improve sharing across processes, we avoid writing to m->_i2i_entry
|
||||
// at runtime. Instead, m->_i2i_entry points to a fixed location inside the CDS archive.
|
||||
// This location contains a trampoline (generated by generate_entry_for_cds_method)
|
||||
// which jumps to _entry_table[kind].
|
||||
address AbstractInterpreter::entry_for_cds_method(const methodHandle& m) {
|
||||
MethodKind kind = method_kind(m);
|
||||
assert(0 <= kind && kind < number_of_method_entries, "illegal kind");
|
||||
return entry_for_cds_method(kind);
|
||||
}
|
||||
|
||||
address AbstractInterpreter::entry_for_cds_method(AbstractInterpreter::MethodKind kind) {
|
||||
const size_t trampoline_size = SharedRuntime::trampoline_size();
|
||||
address addr = MetaspaceShared::i2i_entry_code_buffers();
|
||||
addr += (size_t)(kind) * trampoline_size;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
void AbstractInterpreter::generate_entry_for_cds_method(AbstractInterpreter::MethodKind kind) {
|
||||
if (UseSharedSpaces) {
|
||||
address trampoline = entry_for_cds_method(kind);
|
||||
CodeBuffer buffer(trampoline, (int)(SharedRuntime::trampoline_size()));
|
||||
MacroAssembler _masm(&buffer);
|
||||
SharedRuntime::generate_trampoline(&_masm, _entry_table[kind]);
|
||||
_masm.flush();
|
||||
|
||||
if (PrintInterpreter) {
|
||||
Disassembler::decode(buffer.insts_begin(), buffer.insts_end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void AbstractInterpreter::set_entry_for_kind(AbstractInterpreter::MethodKind kind, address entry) {
|
||||
assert(kind >= method_handle_invoke_FIRST &&
|
||||
kind <= method_handle_invoke_LAST, "late initialization only for MH entry points");
|
||||
assert(_entry_table[kind] == _entry_table[abstract], "previous value must be AME entry");
|
||||
_entry_table[kind] = entry;
|
||||
|
||||
generate_entry_for_cds_method(kind);
|
||||
}
|
||||
|
||||
// Return true if the interpreter can prove that the given bytecode has
|
||||
@ -479,6 +440,5 @@ void AbstractInterpreter::initialize_method_handle_entries() {
|
||||
for (int i = method_handle_invoke_FIRST; i <= method_handle_invoke_LAST; i++) {
|
||||
MethodKind kind = (MethodKind) i;
|
||||
_entry_table[kind] = _entry_table[Interpreter::abstract];
|
||||
Interpreter::generate_entry_for_cds_method(kind);
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +116,6 @@ class AbstractInterpreter: AllStatic {
|
||||
|
||||
// method entry points
|
||||
static address _entry_table[number_of_method_entries]; // entry points for a given method
|
||||
static address _cds_entry_table[number_of_method_entries]; // entry points for methods in the CDS archive
|
||||
static address _native_abi_to_tosca[number_of_result_handlers]; // for native method result handlers
|
||||
static address _slow_signature_handler; // the native method generic (slow) signature handler
|
||||
|
||||
@ -136,11 +135,6 @@ class AbstractInterpreter: AllStatic {
|
||||
static address entry_for_kind(MethodKind k) { assert(0 <= k && k < number_of_method_entries, "illegal kind"); return _entry_table[k]; }
|
||||
static address entry_for_method(const methodHandle& m) { return entry_for_kind(method_kind(m)); }
|
||||
|
||||
// used by class data sharing
|
||||
static address entry_for_cds_method(const methodHandle& m) NOT_CDS_RETURN_(NULL);
|
||||
static address entry_for_cds_method(AbstractInterpreter::MethodKind kind) NOT_CDS_RETURN_(NULL);
|
||||
static void generate_entry_for_cds_method(MethodKind kind) NOT_CDS_RETURN;
|
||||
|
||||
// used for bootstrapping method handles:
|
||||
static void set_entry_for_kind(MethodKind k, address e);
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2021, 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
|
||||
@ -181,7 +181,6 @@ void TemplateInterpreterGenerator::generate_all() {
|
||||
#define method_entry(kind) \
|
||||
{ CodeletMark cm(_masm, "method entry point (kind = " #kind ")"); \
|
||||
Interpreter::_entry_table[Interpreter::kind] = generate_method_entry(Interpreter::kind); \
|
||||
Interpreter::generate_entry_for_cds_method(Interpreter::kind); \
|
||||
}
|
||||
|
||||
// all non-native method kinds
|
||||
|
||||
@ -49,26 +49,6 @@
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
|
||||
ArchiveBuilder* ArchiveBuilder::_current = NULL;
|
||||
class AdapterHandlerEntry;
|
||||
|
||||
class MethodTrampolineInfo {
|
||||
address _c2i_entry_trampoline;
|
||||
AdapterHandlerEntry** _adapter_trampoline;
|
||||
public:
|
||||
address c2i_entry_trampoline() { return _c2i_entry_trampoline; }
|
||||
AdapterHandlerEntry** adapter_trampoline() { return _adapter_trampoline; }
|
||||
void set_c2i_entry_trampoline(address addr) { _c2i_entry_trampoline = addr; }
|
||||
void set_adapter_trampoline(AdapterHandlerEntry** entry) { _adapter_trampoline = entry; }
|
||||
};
|
||||
|
||||
class AdapterToTrampoline : public ResourceHashtable<
|
||||
AdapterHandlerEntry*, MethodTrampolineInfo,
|
||||
primitive_hash<AdapterHandlerEntry*>,
|
||||
primitive_equals<AdapterHandlerEntry*>,
|
||||
941, // prime number
|
||||
ResourceObj::C_HEAP> {};
|
||||
|
||||
static AdapterToTrampoline* _adapter_to_trampoline = NULL;
|
||||
|
||||
ArchiveBuilder::OtherROAllocMark::~OtherROAllocMark() {
|
||||
char* newtop = ArchiveBuilder::current()->_ro_region.top();
|
||||
@ -174,7 +154,6 @@ ArchiveBuilder::ArchiveBuilder() :
|
||||
_mapped_static_archive_bottom(NULL),
|
||||
_mapped_static_archive_top(NULL),
|
||||
_buffer_to_requested_delta(0),
|
||||
_mc_region("mc", MAX_SHARED_DELTA),
|
||||
_rw_region("rw", MAX_SHARED_DELTA),
|
||||
_ro_region("ro", MAX_SHARED_DELTA),
|
||||
_rw_src_objs(),
|
||||
@ -186,8 +165,7 @@ ArchiveBuilder::ArchiveBuilder() :
|
||||
_total_closed_heap_region_size(0),
|
||||
_total_open_heap_region_size(0),
|
||||
_estimated_metaspaceobj_bytes(0),
|
||||
_estimated_hashtable_bytes(0),
|
||||
_estimated_trampoline_bytes(0)
|
||||
_estimated_hashtable_bytes(0)
|
||||
{
|
||||
_klasses = new (ResourceObj::C_HEAP, mtClassShared) GrowableArray<Klass*>(4 * K, mtClassShared);
|
||||
_symbols = new (ResourceObj::C_HEAP, mtClassShared) GrowableArray<Symbol*>(256 * K, mtClassShared);
|
||||
@ -343,13 +321,10 @@ size_t ArchiveBuilder::estimate_archive_size() {
|
||||
size_t dictionary_est = SystemDictionaryShared::estimate_size_for_archive();
|
||||
_estimated_hashtable_bytes = symbol_table_est + dictionary_est;
|
||||
|
||||
_estimated_trampoline_bytes = collect_method_trampolines();
|
||||
|
||||
size_t total = 0;
|
||||
|
||||
total += _estimated_metaspaceobj_bytes;
|
||||
total += _estimated_hashtable_bytes;
|
||||
total += _estimated_trampoline_bytes;
|
||||
|
||||
// allow fragmentation at the end of each dump region
|
||||
total += _total_dump_regions * reserve_alignment();
|
||||
@ -357,7 +332,6 @@ size_t ArchiveBuilder::estimate_archive_size() {
|
||||
log_info(cds)("_estimated_hashtable_bytes = " SIZE_FORMAT " + " SIZE_FORMAT " = " SIZE_FORMAT,
|
||||
symbol_table_est, dictionary_est, _estimated_hashtable_bytes);
|
||||
log_info(cds)("_estimated_metaspaceobj_bytes = " SIZE_FORMAT, _estimated_metaspaceobj_bytes);
|
||||
log_info(cds)("_estimated_trampoline_bytes = " SIZE_FORMAT, _estimated_trampoline_bytes);
|
||||
log_info(cds)("total estimate bytes = " SIZE_FORMAT, total);
|
||||
|
||||
return align_up(total, reserve_alignment());
|
||||
@ -380,7 +354,7 @@ address ArchiveBuilder::reserve_buffer() {
|
||||
|
||||
_buffer_bottom = buffer_bottom;
|
||||
_last_verified_top = buffer_bottom;
|
||||
_current_dump_space = &_mc_region;
|
||||
_current_dump_space = &_rw_region;
|
||||
_num_dump_regions_used = 1;
|
||||
_other_region_used_bytes = 0;
|
||||
_current_dump_space->init(&_shared_rs, &_shared_vs);
|
||||
@ -421,6 +395,12 @@ address ArchiveBuilder::reserve_buffer() {
|
||||
vm_direct_exit(0);
|
||||
}
|
||||
|
||||
if (DumpSharedSpaces) {
|
||||
// We don't want any valid object to be at the very bottom of the archive.
|
||||
// See ArchivePtrMarker::mark_pointer().
|
||||
rw_region()->allocate(16);
|
||||
}
|
||||
|
||||
return buffer_bottom;
|
||||
}
|
||||
|
||||
@ -599,10 +579,9 @@ void ArchiveBuilder::verify_estimate_size(size_t estimate, const char* which) {
|
||||
_other_region_used_bytes = 0;
|
||||
}
|
||||
|
||||
void ArchiveBuilder::dump_rw_region() {
|
||||
void ArchiveBuilder::dump_rw_metadata() {
|
||||
ResourceMark rm;
|
||||
log_info(cds)("Allocating RW objects ... ");
|
||||
start_dump_space(&_rw_region);
|
||||
make_shallow_copies(&_rw_region, &_rw_src_objs);
|
||||
|
||||
#if INCLUDE_CDS_JAVA_HEAP
|
||||
@ -615,7 +594,7 @@ void ArchiveBuilder::dump_rw_region() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void ArchiveBuilder::dump_ro_region() {
|
||||
void ArchiveBuilder::dump_ro_metadata() {
|
||||
ResourceMark rm;
|
||||
log_info(cds)("Allocating RO objects ... ");
|
||||
|
||||
@ -1045,15 +1024,9 @@ public:
|
||||
write_header(mapinfo);
|
||||
write_data(header, header_end, 0);
|
||||
|
||||
DumpRegion* mc_region = &builder->_mc_region;
|
||||
DumpRegion* rw_region = &builder->_rw_region;
|
||||
DumpRegion* ro_region = &builder->_ro_region;
|
||||
|
||||
address mc = address(mc_region->base());
|
||||
address mc_end = address(mc_region->end());
|
||||
write_dump_region("mc region", mc_region);
|
||||
write_data(mc, mc_end, mc + buffer_to_runtime_delta());
|
||||
|
||||
write_dump_region("rw region", rw_region);
|
||||
write_objects(rw_region, &builder->_rw_src_objs);
|
||||
|
||||
@ -1076,7 +1049,7 @@ public:
|
||||
};
|
||||
|
||||
void ArchiveBuilder::print_stats() {
|
||||
_alloc_stats.print_stats(int(_ro_region.used()), int(_rw_region.used()), int(_mc_region.used()));
|
||||
_alloc_stats.print_stats(int(_ro_region.used()), int(_rw_region.used()));
|
||||
}
|
||||
|
||||
void ArchiveBuilder::clean_up_src_obj_table() {
|
||||
@ -1084,106 +1057,6 @@ void ArchiveBuilder::clean_up_src_obj_table() {
|
||||
_src_obj_table.iterate(&cleaner);
|
||||
}
|
||||
|
||||
void ArchiveBuilder::init_mc_region() {
|
||||
if (DumpSharedSpaces) { // these are needed only for static archive
|
||||
// We don't want any valid object to be at the very bottom of the archive.
|
||||
// See ArchivePtrMarker::mark_pointer().
|
||||
mc_region()->allocate(16);
|
||||
|
||||
size_t trampoline_size = SharedRuntime::trampoline_size();
|
||||
size_t buf_size = (size_t)AbstractInterpreter::number_of_method_entries * trampoline_size;
|
||||
MetaspaceShared::set_i2i_entry_code_buffers((address)mc_region()->allocate(buf_size));
|
||||
}
|
||||
|
||||
allocate_method_trampolines();
|
||||
}
|
||||
|
||||
void ArchiveBuilder::allocate_method_trampolines_for(InstanceKlass* ik) {
|
||||
if (ik->methods() != NULL) {
|
||||
for (int j = 0; j < ik->methods()->length(); j++) {
|
||||
// Walk the methods in a deterministic order so that the trampolines are
|
||||
// created in a deterministic order.
|
||||
Method* m = ik->methods()->at(j);
|
||||
AdapterHandlerEntry* ent = m->adapter(); // different methods can share the same AdapterHandlerEntry
|
||||
MethodTrampolineInfo* info = _adapter_to_trampoline->get(ent);
|
||||
if (info->c2i_entry_trampoline() == NULL) {
|
||||
info->set_c2i_entry_trampoline(
|
||||
(address)mc_region()->allocate(SharedRuntime::trampoline_size()));
|
||||
info->set_adapter_trampoline(
|
||||
(AdapterHandlerEntry**)mc_region()->allocate(sizeof(AdapterHandlerEntry*)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ArchiveBuilder::allocate_method_trampolines() {
|
||||
for (int i = 0; i < _klasses->length(); i++) {
|
||||
Klass* k = _klasses->at(i);
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
allocate_method_trampolines_for(ik);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate MethodTrampolineInfo for all Methods that will be archived. Also
|
||||
// return the total number of bytes needed by the method trampolines in the MC
|
||||
// region.
|
||||
size_t ArchiveBuilder::collect_method_trampolines() {
|
||||
size_t total = 0;
|
||||
size_t each_method_bytes =
|
||||
align_up(SharedRuntime::trampoline_size(), BytesPerWord) +
|
||||
align_up(sizeof(AdapterHandlerEntry*), BytesPerWord);
|
||||
|
||||
if (_adapter_to_trampoline == NULL) {
|
||||
_adapter_to_trampoline = new (ResourceObj::C_HEAP, mtClass)AdapterToTrampoline();
|
||||
}
|
||||
int count = 0;
|
||||
for (int i = 0; i < _klasses->length(); i++) {
|
||||
Klass* k = _klasses->at(i);
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
if (ik->methods() != NULL) {
|
||||
for (int j = 0; j < ik->methods()->length(); j++) {
|
||||
Method* m = ik->methods()->at(j);
|
||||
AdapterHandlerEntry* ent = m->adapter(); // different methods can share the same AdapterHandlerEntry
|
||||
bool is_created = false;
|
||||
MethodTrampolineInfo* info = _adapter_to_trampoline->put_if_absent(ent, &is_created);
|
||||
if (is_created) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count == 0) {
|
||||
// We have nothing to archive, but let's avoid having an empty region.
|
||||
total = SharedRuntime::trampoline_size();
|
||||
} else {
|
||||
total = count * each_method_bytes;
|
||||
}
|
||||
return align_up(total, SharedSpaceObjectAlignment);
|
||||
}
|
||||
|
||||
void ArchiveBuilder::update_method_trampolines() {
|
||||
for (int i = 0; i < klasses()->length(); i++) {
|
||||
Klass* k = klasses()->at(i);
|
||||
if (k->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
Array<Method*>* methods = ik->methods();
|
||||
for (int j = 0; j < methods->length(); j++) {
|
||||
Method* m = methods->at(j);
|
||||
AdapterHandlerEntry* ent = m->adapter();
|
||||
MethodTrampolineInfo* info = _adapter_to_trampoline->get(ent);
|
||||
// m is the "copy" of the original Method, but its adapter() field is still valid because
|
||||
// we haven't called make_klasses_shareable() yet.
|
||||
m->set_from_compiled_entry(info->c2i_entry_trampoline());
|
||||
m->set_adapter_trampoline(info->adapter_trampoline());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ArchiveBuilder::write_archive(FileMapInfo* mapinfo,
|
||||
GrowableArray<MemRegion>* closed_heap_regions,
|
||||
GrowableArray<MemRegion>* open_heap_regions,
|
||||
@ -1193,9 +1066,6 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo,
|
||||
// MetaspaceShared::n_regions (internal to hotspot).
|
||||
assert(NUM_CDS_REGIONS == MetaspaceShared::n_regions, "sanity");
|
||||
|
||||
// mc contains the trampoline code for method entries, which are patched at run time,
|
||||
// so it needs to be read/write.
|
||||
write_region(mapinfo, MetaspaceShared::mc, &_mc_region, /*read_only=*/false,/*allow_exec=*/true);
|
||||
write_region(mapinfo, MetaspaceShared::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false);
|
||||
write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false);
|
||||
|
||||
@ -1245,18 +1115,15 @@ void ArchiveBuilder::print_region_stats(FileMapInfo *mapinfo,
|
||||
const size_t bitmap_used = mapinfo->space_at(MetaspaceShared::bm)->used();
|
||||
const size_t bitmap_reserved = mapinfo->space_at(MetaspaceShared::bm)->used_aligned();
|
||||
const size_t total_reserved = _ro_region.reserved() + _rw_region.reserved() +
|
||||
_mc_region.reserved() +
|
||||
bitmap_reserved +
|
||||
_total_closed_heap_region_size +
|
||||
_total_open_heap_region_size;
|
||||
const size_t total_bytes = _ro_region.used() + _rw_region.used() +
|
||||
_mc_region.used() +
|
||||
bitmap_used +
|
||||
_total_closed_heap_region_size +
|
||||
_total_open_heap_region_size;
|
||||
const double total_u_perc = percent_of(total_bytes, total_reserved);
|
||||
|
||||
_mc_region.print(total_reserved);
|
||||
_rw_region.print(total_reserved);
|
||||
_ro_region.print(total_reserved);
|
||||
|
||||
@ -1292,7 +1159,6 @@ void ArchiveBuilder::report_out_of_space(const char* name, size_t needed_bytes)
|
||||
// This is highly unlikely to happen on 64-bits because we have reserved a 4GB space.
|
||||
// On 32-bit we reserve only 256MB so you could run out of space with 100,000 classes
|
||||
// or so.
|
||||
_mc_region.print_out_of_space_msg(name, needed_bytes);
|
||||
_rw_region.print_out_of_space_msg(name, needed_bytes);
|
||||
_ro_region.print_out_of_space_msg(name, needed_bytes);
|
||||
|
||||
|
||||
@ -51,22 +51,20 @@ const int SharedSpaceObjectAlignment = KlassAlignmentInBytes;
|
||||
//
|
||||
// [1] Load all classes (static dump: from the classlist, dynamic dump: as part of app execution)
|
||||
// [2] Allocate "output buffer"
|
||||
// [3] Copy contents of the 3 "core" regions (mc/rw/ro) into the output buffer.
|
||||
// - mc region:
|
||||
// allocate_method_trampolines();
|
||||
// allocate the cpp vtables (static dump only)
|
||||
// [3] Copy contents of the 2 "core" regions (rw/ro) into the output buffer.
|
||||
// - allocate the cpp vtables in rw (static dump only)
|
||||
// - memcpy the MetaspaceObjs into rw/ro:
|
||||
// dump_rw_region();
|
||||
// dump_ro_region();
|
||||
// - fix all the pointers in the MetaspaceObjs to point to the copies
|
||||
// relocate_metaspaceobj_embedded_pointers()
|
||||
// [4] Copy symbol table, dictionary, etc, into the ro region
|
||||
// [5] Relocate all the pointers in mc/rw/ro, so that the archive can be mapped to
|
||||
// [5] Relocate all the pointers in rw/ro, so that the archive can be mapped to
|
||||
// the "requested" location without runtime relocation. See relocate_to_requested()
|
||||
class ArchiveBuilder : public StackObj {
|
||||
protected:
|
||||
DumpRegion* _current_dump_space;
|
||||
address _buffer_bottom; // for writing the contents of mc/rw/ro regions
|
||||
address _buffer_bottom; // for writing the contents of rw/ro regions
|
||||
address _last_verified_top;
|
||||
int _num_dump_regions_used;
|
||||
size_t _other_region_used_bytes;
|
||||
@ -195,7 +193,6 @@ private:
|
||||
ReservedSpace _shared_rs;
|
||||
VirtualSpace _shared_vs;
|
||||
|
||||
DumpRegion _mc_region;
|
||||
DumpRegion _rw_region;
|
||||
DumpRegion _ro_region;
|
||||
CHeapBitMap _ptrmap; // bitmap used by ArchivePtrMarker
|
||||
@ -263,9 +260,8 @@ protected:
|
||||
// Conservative estimate for number of bytes needed for:
|
||||
size_t _estimated_metaspaceobj_bytes; // all archived MetaspaceObj's.
|
||||
size_t _estimated_hashtable_bytes; // symbol table and dictionaries
|
||||
size_t _estimated_trampoline_bytes; // method entry trampolines
|
||||
|
||||
static const int _total_dump_regions = 3;
|
||||
static const int _total_dump_regions = 2;
|
||||
|
||||
size_t estimate_archive_size();
|
||||
|
||||
@ -348,13 +344,9 @@ public:
|
||||
void add_special_ref(MetaspaceClosure::SpecialRef type, address src_obj, size_t field_offset);
|
||||
void remember_embedded_pointer_in_copied_obj(MetaspaceClosure::Ref* enclosing_ref, MetaspaceClosure::Ref* ref);
|
||||
|
||||
DumpRegion* mc_region() { return &_mc_region; }
|
||||
DumpRegion* rw_region() { return &_rw_region; }
|
||||
DumpRegion* ro_region() { return &_ro_region; }
|
||||
|
||||
static char* mc_region_alloc(size_t num_bytes) {
|
||||
return current()->mc_region()->allocate(num_bytes);
|
||||
}
|
||||
static char* rw_region_alloc(size_t num_bytes) {
|
||||
return current()->rw_region()->allocate(num_bytes);
|
||||
}
|
||||
@ -384,9 +376,8 @@ public:
|
||||
return align_up(byte_size, SharedSpaceObjectAlignment);
|
||||
}
|
||||
|
||||
void init_mc_region();
|
||||
void dump_rw_region();
|
||||
void dump_ro_region();
|
||||
void dump_rw_metadata();
|
||||
void dump_ro_metadata();
|
||||
void relocate_metaspaceobj_embedded_pointers();
|
||||
void relocate_roots();
|
||||
void relocate_vm_classes();
|
||||
@ -442,12 +433,6 @@ public:
|
||||
|
||||
void print_stats();
|
||||
void report_out_of_space(const char* name, size_t needed_bytes);
|
||||
|
||||
// Method trampolines related functions
|
||||
size_t collect_method_trampolines();
|
||||
void allocate_method_trampolines();
|
||||
void allocate_method_trampolines_for(InstanceKlass* ik);
|
||||
void update_method_trampolines();
|
||||
};
|
||||
|
||||
#endif // SHARE_MEMORY_ARCHIVEBUILDER_HPP
|
||||
|
||||
@ -101,7 +101,7 @@ template <class T>
|
||||
CppVtableInfo* CppVtableCloner<T>::allocate_and_initialize(const char* name) {
|
||||
int n = get_vtable_length(name);
|
||||
CppVtableInfo* info =
|
||||
(CppVtableInfo*)ArchiveBuilder::current()->mc_region()->allocate(CppVtableInfo::byte_size(n));
|
||||
(CppVtableInfo*)ArchiveBuilder::current()->rw_region()->allocate(CppVtableInfo::byte_size(n));
|
||||
info->set_vtable_size(n);
|
||||
initialize(name, info);
|
||||
return info;
|
||||
@ -212,13 +212,16 @@ void CppVtableCloner<T>::init_orig_cpp_vtptr(int kind) {
|
||||
// _index[InstanceKlass_Kind]->cloned_vtable() == ((intptr_t**)ik)[0]
|
||||
CppVtableInfo** CppVtables::_index = NULL;
|
||||
|
||||
char* CppVtables::dumptime_init() {
|
||||
char* CppVtables::dumptime_init(ArchiveBuilder* builder) {
|
||||
assert(DumpSharedSpaces, "must");
|
||||
size_t vtptrs_bytes = _num_cloned_vtable_kinds * sizeof(CppVtableInfo*);
|
||||
_index = (CppVtableInfo**)ArchiveBuilder::current()->mc_region()->allocate(vtptrs_bytes);
|
||||
_index = (CppVtableInfo**)builder->rw_region()->allocate(vtptrs_bytes);
|
||||
|
||||
CPP_VTABLE_TYPES_DO(ALLOCATE_AND_INITIALIZE_VTABLE);
|
||||
|
||||
size_t cpp_tables_size = builder->rw_region()->top() - builder->rw_region()->base();
|
||||
builder->alloc_stats()->record_cpp_vtables((int)cpp_tables_size);
|
||||
|
||||
return (char*)_index;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2021, 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
|
||||
@ -29,6 +29,7 @@
|
||||
#include "memory/allStatic.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class ArchiveBuilder;
|
||||
class Method;
|
||||
class SerializeClosure;
|
||||
class CppVtableInfo;
|
||||
@ -37,7 +38,7 @@ class CppVtableInfo;
|
||||
class CppVtables : AllStatic {
|
||||
static CppVtableInfo** _index;
|
||||
public:
|
||||
static char* dumptime_init();
|
||||
static char* dumptime_init(ArchiveBuilder* builder);
|
||||
static void zero_archived_vtables();
|
||||
static intptr_t* get_archived_vtable(MetaspaceObj::Type msotype, address obj);
|
||||
static void serialize(SerializeClosure* sc);
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
#include "logging/logMessage.hpp"
|
||||
#include "memory/dumpAllocStats.hpp"
|
||||
|
||||
void DumpAllocStats::print_stats(int ro_all, int rw_all, int mc_all) {
|
||||
void DumpAllocStats::print_stats(int ro_all, int rw_all) {
|
||||
// symbols
|
||||
_counts[RO][SymbolHashentryType] = _symbol_stats.hashentry_count;
|
||||
_bytes [RO][SymbolHashentryType] = _symbol_stats.hashentry_bytes;
|
||||
@ -42,10 +42,6 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all, int mc_all) {
|
||||
_counts[RO][StringBucketType] = _string_stats.bucket_count;
|
||||
_bytes [RO][StringBucketType] = _string_stats.bucket_bytes;
|
||||
|
||||
// TODO: count things like dictionary, vtable, etc
|
||||
_bytes[RW][OtherType] += mc_all;
|
||||
rw_all += mc_all; // mc is mapped Read/Write
|
||||
|
||||
// prevent divide-by-zero
|
||||
if (ro_all < 1) {
|
||||
ro_all = 1;
|
||||
@ -66,7 +62,7 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all, int mc_all) {
|
||||
|
||||
LogMessage(cds) msg;
|
||||
|
||||
msg.debug("Detailed metadata info (excluding heap regions; rw stats include mc regions):");
|
||||
msg.debug("Detailed metadata info (excluding heap regions):");
|
||||
msg.debug("%s", hdr);
|
||||
msg.debug("%s", sep);
|
||||
for (int type = 0; type < int(_number_of_types); type ++) {
|
||||
@ -111,4 +107,3 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all, int mc_all) {
|
||||
|
||||
#undef fmt_stats
|
||||
}
|
||||
|
||||
|
||||
@ -41,6 +41,7 @@ public:
|
||||
f(StringHashentry) \
|
||||
f(StringBucket) \
|
||||
f(ModulesNatives) \
|
||||
f(CppVTables) \
|
||||
f(Other)
|
||||
|
||||
enum Type {
|
||||
@ -91,7 +92,12 @@ public:
|
||||
int which = (read_only) ? RO : RW;
|
||||
_bytes [which][OtherType] += byte_size;
|
||||
}
|
||||
void print_stats(int ro_all, int rw_all, int mc_all);
|
||||
|
||||
void record_cpp_vtables(int byte_size) {
|
||||
_bytes[RW][CppVTablesType] += byte_size;
|
||||
}
|
||||
|
||||
void print_stats(int ro_all, int rw_all);
|
||||
};
|
||||
|
||||
#endif // SHARE_MEMORY_DUMPALLOCSTATS_HPP
|
||||
|
||||
@ -116,13 +116,10 @@ public:
|
||||
gather_source_objs();
|
||||
reserve_buffer();
|
||||
|
||||
init_mc_region();
|
||||
verify_estimate_size(_estimated_trampoline_bytes, "Trampolines");
|
||||
|
||||
log_info(cds, dynamic)("Copying %d klasses and %d symbols",
|
||||
klasses()->length(), symbols()->length());
|
||||
dump_rw_region();
|
||||
dump_ro_region();
|
||||
dump_rw_metadata();
|
||||
dump_ro_metadata();
|
||||
relocate_metaspaceobj_embedded_pointers();
|
||||
relocate_roots();
|
||||
|
||||
@ -148,7 +145,6 @@ public:
|
||||
|
||||
verify_estimate_size(_estimated_hashtable_bytes, "Hashtables");
|
||||
|
||||
update_method_trampolines();
|
||||
sort_methods();
|
||||
|
||||
log_info(cds)("Make classes shareable");
|
||||
|
||||
@ -280,7 +280,6 @@ void FileMapHeader::print(outputStream* st) {
|
||||
st->print_cr("- compressed_class_ptrs: %d", _compressed_class_ptrs);
|
||||
st->print_cr("- cloned_vtables_offset: " SIZE_FORMAT_HEX, _cloned_vtables_offset);
|
||||
st->print_cr("- serialized_data_offset: " SIZE_FORMAT_HEX, _serialized_data_offset);
|
||||
st->print_cr("- i2i_entry_code_buffers_offset: " SIZE_FORMAT_HEX, _i2i_entry_code_buffers_offset);
|
||||
st->print_cr("- heap_end: " INTPTR_FORMAT, p2i(_heap_end));
|
||||
st->print_cr("- base_archive_is_default: %d", _base_archive_is_default);
|
||||
st->print_cr("- jvm_ident: %s", _jvm_ident);
|
||||
@ -1271,7 +1270,7 @@ void FileMapRegion::init(int region_index, size_t mapping_offset, size_t size, b
|
||||
|
||||
static const char* region_name(int region_index) {
|
||||
static const char* names[] = {
|
||||
"mc", "rw", "ro", "bm", "ca0", "ca1", "oa0", "oa1"
|
||||
"rw", "ro", "bm", "ca0", "ca1", "oa0", "oa1"
|
||||
};
|
||||
const int num_regions = sizeof(names)/sizeof(names[0]);
|
||||
assert(0 <= region_index && region_index < num_regions, "sanity");
|
||||
@ -1532,7 +1531,7 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() {
|
||||
}
|
||||
|
||||
// Memory map a region in the address space.
|
||||
static const char* shared_region_name[] = { "MiscCode", "ReadWrite", "ReadOnly", "Bitmap",
|
||||
static const char* shared_region_name[] = { "ReadWrite", "ReadOnly", "Bitmap",
|
||||
"String1", "String2", "OpenArchive1", "OpenArchive2" };
|
||||
|
||||
MapArchiveResult FileMapInfo::map_regions(int regions[], int num_regions, char* mapped_base_address, ReservedSpace rs) {
|
||||
@ -1677,7 +1676,7 @@ char* FileMapInfo::map_bitmap_region() {
|
||||
}
|
||||
|
||||
// This is called when we cannot map the archive at the requested[ base address (usually 0x800000000).
|
||||
// We relocate all pointers in the 3 core regions (mc, ro, rw).
|
||||
// We relocate all pointers in the 2 core regions (ro, rw).
|
||||
bool FileMapInfo::relocate_pointers_in_core_regions(intx addr_delta) {
|
||||
log_debug(cds, reloc)("runtime archive relocation start");
|
||||
char* bitmap_base = map_bitmap_region();
|
||||
@ -2172,9 +2171,9 @@ char* FileMapInfo::region_addr(int idx) {
|
||||
}
|
||||
}
|
||||
|
||||
// The 3 core spaces are MC->RW->RO
|
||||
// The 2 core spaces are RW->RO
|
||||
FileMapRegion* FileMapInfo::first_core_space() const {
|
||||
return space_at(MetaspaceShared::mc);
|
||||
return space_at(MetaspaceShared::rw);
|
||||
}
|
||||
|
||||
FileMapRegion* FileMapInfo::last_core_space() const {
|
||||
@ -2280,8 +2279,7 @@ bool FileMapInfo::validate_header() {
|
||||
// Check if a given address is within one of the shared regions
|
||||
bool FileMapInfo::is_in_shared_region(const void* p, int idx) {
|
||||
assert(idx == MetaspaceShared::ro ||
|
||||
idx == MetaspaceShared::rw ||
|
||||
idx == MetaspaceShared::mc, "invalid region index");
|
||||
idx == MetaspaceShared::rw, "invalid region index");
|
||||
char* base = region_addr(idx);
|
||||
if (p >= base && p < base + space_at(idx)->used()) {
|
||||
return true;
|
||||
|
||||
@ -30,14 +30,11 @@
|
||||
#include "oops/compressedOops.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
|
||||
// Layout of the file:
|
||||
// header: dump of archive instance plus versioning info, datestamp, etc.
|
||||
// [magic # = 0xF00BABA2]
|
||||
// ... padding to align on page-boundary
|
||||
// read-write space
|
||||
// read-only space
|
||||
// misc data (block offset table, string table, symbols, dictionary, etc.)
|
||||
// tag(666)
|
||||
// To understand the layout of the CDS archive file:
|
||||
//
|
||||
// java -Xlog:cds+map=info:file=cds.map:none:filesize=0
|
||||
// java -Xlog:cds+map=debug:file=cds.map:none:filesize=0
|
||||
// java -Xlog:cds+map=trace:file=cds.map:none:filesize=0
|
||||
|
||||
static const int JVM_IDENT_MAX = 256;
|
||||
|
||||
@ -202,7 +199,6 @@ class FileMapHeader: private CDSFileMapHeaderBase {
|
||||
bool _compressed_class_ptrs; // save the flag UseCompressedClassPointers
|
||||
size_t _cloned_vtables_offset; // The address of the first cloned vtable
|
||||
size_t _serialized_data_offset; // Data accessed using {ReadClosure,WriteClosure}::serialize()
|
||||
size_t _i2i_entry_code_buffers_offset;
|
||||
address _heap_end; // heap end at dump time.
|
||||
bool _base_archive_is_default; // indicates if the base archive is the system default one
|
||||
|
||||
@ -266,7 +262,6 @@ public:
|
||||
address narrow_klass_base() const { return (address)mapped_base_address(); }
|
||||
char* cloned_vtables() const { return from_mapped_offset(_cloned_vtables_offset); }
|
||||
char* serialized_data() const { return from_mapped_offset(_serialized_data_offset); }
|
||||
address i2i_entry_code_buffers() const { return (address)from_mapped_offset(_i2i_entry_code_buffers_offset); }
|
||||
address heap_end() const { return _heap_end; }
|
||||
bool base_archive_is_default() const { return _base_archive_is_default; }
|
||||
const char* jvm_ident() const { return _jvm_ident; }
|
||||
@ -293,9 +288,6 @@ public:
|
||||
void set_ptrmap_size_in_bits(size_t s) { _ptrmap_size_in_bits = s; }
|
||||
void set_mapped_base_address(char* p) { _mapped_base_address = p; }
|
||||
void set_heap_obj_roots(narrowOop r) { _heap_obj_roots = r; }
|
||||
void set_i2i_entry_code_buffers(address p) {
|
||||
set_as_offset((char*)p, &_i2i_entry_code_buffers_offset);
|
||||
}
|
||||
|
||||
void set_shared_path_table(SharedPathTable table) {
|
||||
set_as_offset((char*)table.table(), &_shared_path_table_offset);
|
||||
@ -410,11 +402,6 @@ public:
|
||||
bool is_file_position_aligned() const;
|
||||
void align_file_position();
|
||||
|
||||
address i2i_entry_code_buffers() const { return header()->i2i_entry_code_buffers(); }
|
||||
void set_i2i_entry_code_buffers(address addr) const {
|
||||
header()->set_i2i_entry_code_buffers(addr);
|
||||
}
|
||||
|
||||
bool is_static() const { return _is_static; }
|
||||
bool is_mapped() const { return _is_mapped; }
|
||||
void set_is_mapped(bool v) { _is_mapped = v; }
|
||||
|
||||
@ -81,7 +81,6 @@ VirtualSpace MetaspaceShared::_symbol_vs;
|
||||
bool MetaspaceShared::_has_error_classes;
|
||||
bool MetaspaceShared::_archive_loading_failed = false;
|
||||
bool MetaspaceShared::_remapped_readwrite = false;
|
||||
address MetaspaceShared::_i2i_entry_code_buffers = NULL;
|
||||
void* MetaspaceShared::_shared_metaspace_static_top = NULL;
|
||||
intx MetaspaceShared::_relocation_delta;
|
||||
char* MetaspaceShared::_requested_base_address;
|
||||
@ -89,7 +88,6 @@ bool MetaspaceShared::_use_optimized_module_handling = true;
|
||||
bool MetaspaceShared::_use_full_module_graph = true;
|
||||
|
||||
// The CDS archive is divided into the following regions:
|
||||
// mc - misc code (the method entry trampolines, c++ vtables)
|
||||
// rw - read-write metadata
|
||||
// ro - read-only metadata and read-only tables
|
||||
//
|
||||
@ -100,21 +98,21 @@ bool MetaspaceShared::_use_full_module_graph = true;
|
||||
//
|
||||
// bm - bitmap for relocating the above 7 regions.
|
||||
//
|
||||
// The mc, rw, and ro regions are linearly allocated, in the order of mc->rw->ro.
|
||||
// The rw, and ro regions are linearly allocated, in the order of rw->ro.
|
||||
// These regions are aligned with MetaspaceShared::reserved_space_alignment().
|
||||
//
|
||||
// These 3 regions are populated in the following steps:
|
||||
// These 2 regions are populated in the following steps:
|
||||
// [0] All classes are loaded in MetaspaceShared::preload_classes(). All metadata are
|
||||
// temporarily allocated outside of the shared regions.
|
||||
// [1] We enter a safepoint and allocate a buffer for the mc/rw/ro regions.
|
||||
// [2] C++ vtables and method trampolines are copied into the mc region.
|
||||
// [1] We enter a safepoint and allocate a buffer for the rw/ro regions.
|
||||
// [2] C++ vtables are copied into the rw region.
|
||||
// [3] ArchiveBuilder copies RW metadata into the rw region.
|
||||
// [4] ArchiveBuilder copies RO metadata into the ro region.
|
||||
// [5] SymbolTable, StringTable, SystemDictionary, and a few other read-only data
|
||||
// are copied into the ro region as read-only tables.
|
||||
//
|
||||
// The ca0/ca1 and oa0/oa1 regions are populated inside HeapShared::archive_java_heap_objects.
|
||||
// Their layout is independent of the mc/rw/ro regions.
|
||||
// Their layout is independent of the rw/ro regions.
|
||||
|
||||
static DumpRegion _symbol_region("symbols");
|
||||
|
||||
@ -322,18 +320,6 @@ void MetaspaceShared::serialize(SerializeClosure* soc) {
|
||||
soc->do_tag(666);
|
||||
}
|
||||
|
||||
void MetaspaceShared::set_i2i_entry_code_buffers(address b) {
|
||||
assert(DumpSharedSpaces, "must be");
|
||||
assert(_i2i_entry_code_buffers == NULL, "initialize only once");
|
||||
_i2i_entry_code_buffers = b;
|
||||
}
|
||||
|
||||
address MetaspaceShared::i2i_entry_code_buffers() {
|
||||
assert(DumpSharedSpaces || UseSharedSpaces, "must be");
|
||||
assert(_i2i_entry_code_buffers != NULL, "must already been initialized");
|
||||
return _i2i_entry_code_buffers;
|
||||
}
|
||||
|
||||
static void rewrite_nofast_bytecode(const methodHandle& method) {
|
||||
BytecodeStream bcs(method);
|
||||
while (!bcs.is_last_bytecode()) {
|
||||
@ -472,11 +458,10 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
builder.gather_source_objs();
|
||||
builder.reserve_buffer();
|
||||
|
||||
builder.init_mc_region();
|
||||
char* cloned_vtables = CppVtables::dumptime_init();
|
||||
char* cloned_vtables = CppVtables::dumptime_init(&builder);
|
||||
|
||||
builder.dump_rw_region();
|
||||
builder.dump_ro_region();
|
||||
builder.dump_rw_metadata();
|
||||
builder.dump_ro_metadata();
|
||||
builder.relocate_metaspaceobj_embedded_pointers();
|
||||
|
||||
// Dump supported java heap objects
|
||||
@ -489,9 +474,6 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
|
||||
builder.relocate_vm_classes();
|
||||
|
||||
log_info(cds)("Update method trampolines");
|
||||
builder.update_method_trampolines();
|
||||
|
||||
log_info(cds)("Make classes shareable");
|
||||
builder.make_klasses_shareable();
|
||||
|
||||
@ -500,7 +482,7 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
SystemDictionaryShared::adjust_lambda_proxy_class_dictionary();
|
||||
|
||||
// The vtable clones contain addresses of the current process.
|
||||
// We don't want to write these addresses into the archive. Same for i2i buffer.
|
||||
// We don't want to write these addresses into the archive.
|
||||
CppVtables::zero_archived_vtables();
|
||||
|
||||
// relocate the data so that it can be mapped to MetaspaceShared::requested_base_address()
|
||||
@ -512,7 +494,6 @@ void VM_PopulateDumpSharedSpace::doit() {
|
||||
mapinfo->populate_header(os::vm_allocation_granularity());
|
||||
mapinfo->set_serialized_data(serialized_data);
|
||||
mapinfo->set_cloned_vtables(cloned_vtables);
|
||||
mapinfo->set_i2i_entry_code_buffers(MetaspaceShared::i2i_entry_code_buffers());
|
||||
mapinfo->open_for_write();
|
||||
builder.write_archive(mapinfo,
|
||||
_closed_archive_heap_regions,
|
||||
@ -856,13 +837,6 @@ bool MetaspaceShared::is_in_shared_region(const void* p, int idx) {
|
||||
return UseSharedSpaces && FileMapInfo::current_info()->is_in_shared_region(p, idx);
|
||||
}
|
||||
|
||||
bool MetaspaceShared::is_in_trampoline_frame(address addr) {
|
||||
if (UseSharedSpaces && is_in_shared_region(addr, MetaspaceShared::mc)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MetaspaceShared::is_shared_dynamic(void* p) {
|
||||
if ((p < MetaspaceObj::shared_metaspace_top()) &&
|
||||
(p >= _shared_metaspace_static_top)) {
|
||||
@ -1315,10 +1289,8 @@ void MetaspaceShared::release_reserved_spaces(ReservedSpace& total_space_rs,
|
||||
}
|
||||
}
|
||||
|
||||
static int archive_regions[] = {MetaspaceShared::mc,
|
||||
MetaspaceShared::rw,
|
||||
MetaspaceShared::ro};
|
||||
static int archive_regions_count = 3;
|
||||
static int archive_regions[] = { MetaspaceShared::rw, MetaspaceShared::ro };
|
||||
static int archive_regions_count = 2;
|
||||
|
||||
MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped_base_address, ReservedSpace rs) {
|
||||
assert(UseSharedSpaces, "must be runtime");
|
||||
@ -1365,7 +1337,6 @@ void MetaspaceShared::unmap_archive(FileMapInfo* mapinfo) {
|
||||
|
||||
void MetaspaceShared::initialize_shared_spaces() {
|
||||
FileMapInfo *static_mapinfo = FileMapInfo::current_info();
|
||||
_i2i_entry_code_buffers = static_mapinfo->i2i_entry_code_buffers();
|
||||
|
||||
// Verify various attributes of the archive, plus initialize the
|
||||
// shared string/symbol tables
|
||||
|
||||
@ -50,7 +50,6 @@ class MetaspaceShared : AllStatic {
|
||||
static bool _has_error_classes;
|
||||
static bool _archive_loading_failed;
|
||||
static bool _remapped_readwrite;
|
||||
static address _i2i_entry_code_buffers;
|
||||
static void* _shared_metaspace_static_top;
|
||||
static intx _relocation_delta;
|
||||
static char* _requested_base_address;
|
||||
@ -59,12 +58,11 @@ class MetaspaceShared : AllStatic {
|
||||
public:
|
||||
enum {
|
||||
// core archive spaces
|
||||
mc = 0, // miscellaneous code for method trampolines
|
||||
rw = 1, // read-write shared space in the heap
|
||||
ro = 2, // read-only shared space in the heap
|
||||
bm = 3, // relocation bitmaps (freed after file mapping is finished)
|
||||
num_core_region = 3,
|
||||
num_non_heap_spaces = 4,
|
||||
rw = 0, // read-write shared space in the heap
|
||||
ro = 1, // read-only shared space in the heap
|
||||
bm = 2, // relocation bitmaps (freed after file mapping is finished)
|
||||
num_core_region = 2, // rw and ro
|
||||
num_non_heap_spaces = 3, // rw and ro and bm
|
||||
|
||||
// mapped java heap regions
|
||||
first_closed_archive_heap_region = bm + 1,
|
||||
@ -115,8 +113,6 @@ class MetaspaceShared : AllStatic {
|
||||
// Return true if given address is in the shared region corresponding to the idx
|
||||
static bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
|
||||
|
||||
static bool is_in_trampoline_frame(address addr) NOT_CDS_RETURN_(false);
|
||||
|
||||
static bool is_shared_dynamic(void* p) NOT_CDS_RETURN_(false);
|
||||
|
||||
static void serialize(SerializeClosure* sc) NOT_CDS_RETURN;
|
||||
@ -144,10 +140,6 @@ class MetaspaceShared : AllStatic {
|
||||
// Allocate a block of memory from the temporary "symbol" region.
|
||||
static char* symbol_space_alloc(size_t num_bytes);
|
||||
|
||||
static void init_misc_code_space();
|
||||
static address i2i_entry_code_buffers();
|
||||
static void set_i2i_entry_code_buffers(address b);
|
||||
|
||||
// This is the base address as specified by -XX:SharedBaseAddress during -Xshare:dump.
|
||||
// Both the base/top archives are written using this as their base address.
|
||||
//
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2021, 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
|
||||
@ -421,16 +421,6 @@ void ConstMethod::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
it->push(default_annotations_addr());
|
||||
}
|
||||
ConstMethod* this_ptr = this;
|
||||
it->push_method_entry(&this_ptr, (intptr_t*)&_adapter_trampoline);
|
||||
}
|
||||
|
||||
void ConstMethod::set_adapter_trampoline(AdapterHandlerEntry** trampoline) {
|
||||
Arguments::assert_is_dumping_archive();
|
||||
if (DumpSharedSpaces) {
|
||||
assert(*trampoline == NULL,
|
||||
"must be NULL during dump time, to be initialized at run time");
|
||||
}
|
||||
_adapter_trampoline = trampoline;
|
||||
}
|
||||
|
||||
// Printing
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2021, 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
|
||||
@ -121,8 +121,6 @@ class MethodParametersElement {
|
||||
u2 flags;
|
||||
};
|
||||
|
||||
class AdapterHandlerEntry;
|
||||
|
||||
// Class to collect the sizes of ConstMethod inline tables
|
||||
#define INLINE_TABLES_DO(do_element) \
|
||||
do_element(localvariable_table_length) \
|
||||
@ -205,12 +203,6 @@ private:
|
||||
// Raw stackmap data for the method
|
||||
Array<u1>* _stackmap_data;
|
||||
|
||||
// Adapter blob (i2c/c2i) for this Method*. Set once when method is linked.
|
||||
union {
|
||||
AdapterHandlerEntry* _adapter;
|
||||
AdapterHandlerEntry** _adapter_trampoline; // see comments around Method::link_method()
|
||||
};
|
||||
|
||||
int _constMethod_size;
|
||||
u2 _flags;
|
||||
u1 _result_type; // BasicType of result
|
||||
@ -285,26 +277,6 @@ public:
|
||||
void copy_stackmap_data(ClassLoaderData* loader_data, u1* sd, int length, TRAPS);
|
||||
bool has_stackmap_table() const { return _stackmap_data != NULL; }
|
||||
|
||||
// adapter
|
||||
void set_adapter_entry(AdapterHandlerEntry* adapter) {
|
||||
assert(!is_shared(),
|
||||
"shared methods in archive have fixed adapter_trampoline");
|
||||
_adapter = adapter;
|
||||
}
|
||||
void set_adapter_trampoline(AdapterHandlerEntry** trampoline);
|
||||
void update_adapter_trampoline(AdapterHandlerEntry* adapter) {
|
||||
assert(is_shared(), "must be");
|
||||
*_adapter_trampoline = adapter;
|
||||
assert(this->adapter() == adapter, "must be");
|
||||
}
|
||||
AdapterHandlerEntry* adapter() {
|
||||
if (is_shared()) {
|
||||
return *_adapter_trampoline;
|
||||
} else {
|
||||
return _adapter;
|
||||
}
|
||||
}
|
||||
|
||||
void init_fingerprint() {
|
||||
const uint64_t initval = UCONST64(0x8000000000000000);
|
||||
_fingerprint = initval;
|
||||
|
||||
@ -350,9 +350,6 @@ void Method::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
it->push(&_method_counters);
|
||||
|
||||
Method* this_ptr = this;
|
||||
it->push_method_entry(&this_ptr, (intptr_t*)&_i2i_entry);
|
||||
it->push_method_entry(&this_ptr, (intptr_t*)&_from_compiled_entry);
|
||||
it->push_method_entry(&this_ptr, (intptr_t*)&_from_interpreted_entry);
|
||||
}
|
||||
|
||||
// Attempt to return method to original state. Clear any pointers
|
||||
@ -1113,17 +1110,12 @@ void Method::unlink_code() {
|
||||
#if INCLUDE_CDS
|
||||
// Called by class data sharing to remove any entry points (which are not shared)
|
||||
void Method::unlink_method() {
|
||||
_code = NULL;
|
||||
|
||||
Arguments::assert_is_dumping_archive();
|
||||
// Set the values to what they should be at run time. Note that
|
||||
// this Method can no longer be executed during dump time.
|
||||
_i2i_entry = Interpreter::entry_for_cds_method(methodHandle(Thread::current(), this));
|
||||
_from_interpreted_entry = _i2i_entry;
|
||||
|
||||
assert(_from_compiled_entry != NULL, "sanity");
|
||||
assert(*((int*)_from_compiled_entry) == 0,
|
||||
"must be NULL during dump time, to be initialized at run time");
|
||||
_code = NULL;
|
||||
_adapter = NULL;
|
||||
_i2i_entry = NULL;
|
||||
_from_compiled_entry = NULL;
|
||||
_from_interpreted_entry = NULL;
|
||||
|
||||
if (is_native()) {
|
||||
*native_function_addr() = NULL;
|
||||
@ -1136,90 +1128,12 @@ void Method::unlink_method() {
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
// The following illustrates how the entries work for CDS shared Methods:
|
||||
//
|
||||
// Our goal is to delay writing into a shared Method until it's compiled.
|
||||
// Hence, we want to determine the initial values for _i2i_entry,
|
||||
// _from_interpreted_entry and _from_compiled_entry during CDS dump time.
|
||||
//
|
||||
// In this example, both Methods A and B have the _i2i_entry of "zero_locals".
|
||||
// They also have similar signatures so that they will share the same
|
||||
// AdapterHandlerEntry.
|
||||
//
|
||||
// _adapter_trampoline points to a fixed location in the RW section of
|
||||
// the CDS archive. This location initially contains a NULL pointer. When the
|
||||
// first of method A or B is linked, an AdapterHandlerEntry is allocated
|
||||
// dynamically, and its c2i/i2c entries are generated.
|
||||
//
|
||||
// _i2i_entry and _from_interpreted_entry initially points to the same
|
||||
// (fixed) location in the CODE section of the CDS archive. This contains
|
||||
// an unconditional branch to the actual entry for "zero_locals", which is
|
||||
// generated at run time and may be on an arbitrary address. Thus, the
|
||||
// unconditional branch is also generated at run time to jump to the correct
|
||||
// address.
|
||||
//
|
||||
// Similarly, _from_compiled_entry points to a fixed address in the CODE
|
||||
// section. This address has enough space for an unconditional branch
|
||||
// instruction, and is initially zero-filled. After the AdapterHandlerEntry is
|
||||
// initialized, and the address for the actual c2i_entry is known, we emit a
|
||||
// branch instruction here to branch to the actual c2i_entry.
|
||||
//
|
||||
// The effect of the extra branch on the i2i and c2i entries is negligible.
|
||||
//
|
||||
// The reason for putting _adapter_trampoline in RO is many shared Methods
|
||||
// share the same AdapterHandlerEntry, so we can save space in the RW section
|
||||
// by having the extra indirection.
|
||||
|
||||
|
||||
[Method A: RW]
|
||||
_constMethod ----> [ConstMethod: RO]
|
||||
_adapter_trampoline -----------+
|
||||
|
|
||||
_i2i_entry (same value as method B) |
|
||||
_from_interpreted_entry (same value as method B) |
|
||||
_from_compiled_entry (same value as method B) |
|
||||
|
|
||||
|
|
||||
[Method B: RW] +--------+
|
||||
_constMethod ----> [ConstMethod: RO] |
|
||||
_adapter_trampoline --+--->(AdapterHandlerEntry* ptr: RW)-+
|
||||
|
|
||||
+-------------------------------+
|
||||
|
|
||||
+----> [AdapterHandlerEntry] (allocated at run time)
|
||||
_fingerprint
|
||||
_c2i_entry ---------------------------------+->[c2i entry..]
|
||||
_i2i_entry -------------+ _i2c_entry ---------------+-> [i2c entry..] |
|
||||
_from_interpreted_entry | _c2i_unverified_entry | |
|
||||
| | _c2i_no_clinit_check_entry| |
|
||||
| | (_cds_entry_table: CODE) | |
|
||||
| +->[0]: jmp _entry_table[0] --> (i2i_entry_for "zero_locals") | |
|
||||
| | (allocated at run time) | |
|
||||
| | ... [asm code ...] | |
|
||||
+-[not compiled]-+ [n]: jmp _entry_table[n] | |
|
||||
| | |
|
||||
| | |
|
||||
+-[compiled]-------------------------------------------------------------------+ |
|
||||
|
|
||||
_from_compiled_entry------------> (_c2i_entry_trampoline: CODE) |
|
||||
[jmp c2i_entry] ------------------------------------------------------+
|
||||
|
||||
***/
|
||||
|
||||
// Called when the method_holder is getting linked. Setup entrypoints so the method
|
||||
// is ready to be called from interpreter, compiler, and vtables.
|
||||
void Method::link_method(const methodHandle& h_method, TRAPS) {
|
||||
// If the code cache is full, we may reenter this function for the
|
||||
// leftover methods that weren't linked.
|
||||
if (is_shared()) {
|
||||
// Can't assert that the adapters are sane, because methods get linked before
|
||||
// the interpreter is generated, and hence before its adapters are generated.
|
||||
// If you messed them up you will notice soon enough though, don't you worry.
|
||||
if (adapter() != NULL) {
|
||||
return;
|
||||
}
|
||||
} else if (_i2i_entry != NULL) {
|
||||
if (_i2i_entry != NULL) {
|
||||
return;
|
||||
}
|
||||
assert( _code == NULL, "nothing compiled yet" );
|
||||
@ -1227,13 +1141,11 @@ void Method::link_method(const methodHandle& h_method, TRAPS) {
|
||||
// Setup interpreter entrypoint
|
||||
assert(this == h_method(), "wrong h_method()" );
|
||||
|
||||
if (!is_shared()) {
|
||||
assert(adapter() == NULL, "init'd to NULL");
|
||||
address entry = Interpreter::entry_for_method(h_method);
|
||||
assert(entry != NULL, "interpreter entry must be non-null");
|
||||
// Sets both _i2i_entry and _from_interpreted_entry
|
||||
set_interpreter_entry(entry);
|
||||
}
|
||||
assert(adapter() == NULL, "init'd to NULL");
|
||||
address entry = Interpreter::entry_for_method(h_method);
|
||||
assert(entry != NULL, "interpreter entry must be non-null");
|
||||
// Sets both _i2i_entry and _from_interpreted_entry
|
||||
set_interpreter_entry(entry);
|
||||
|
||||
// Don't overwrite already registered native entries.
|
||||
if (is_native() && !has_native_function()) {
|
||||
@ -1253,7 +1165,6 @@ void Method::link_method(const methodHandle& h_method, TRAPS) {
|
||||
(void) make_adapters(h_method, CHECK);
|
||||
|
||||
// ONLY USE the h_method now as make_adapter may have blocked
|
||||
|
||||
}
|
||||
|
||||
address Method::make_adapters(const methodHandle& mh, TRAPS) {
|
||||
@ -1272,25 +1183,13 @@ address Method::make_adapters(const methodHandle& mh, TRAPS) {
|
||||
}
|
||||
}
|
||||
|
||||
if (mh->is_shared()) {
|
||||
assert(mh->adapter() == adapter, "must be");
|
||||
assert(mh->_from_compiled_entry != NULL, "must be");
|
||||
} else {
|
||||
mh->set_adapter_entry(adapter);
|
||||
mh->_from_compiled_entry = adapter->get_c2i_entry();
|
||||
}
|
||||
mh->set_adapter_entry(adapter);
|
||||
mh->_from_compiled_entry = adapter->get_c2i_entry();
|
||||
return adapter->get_c2i_entry();
|
||||
}
|
||||
|
||||
void Method::restore_unshareable_info(TRAPS) {
|
||||
assert(is_method() && is_valid_method(this), "ensure C++ vtable is restored");
|
||||
|
||||
// Since restore_unshareable_info can be called more than once for a method, don't
|
||||
// redo any work.
|
||||
if (adapter() == NULL) {
|
||||
methodHandle mh(THREAD, this);
|
||||
link_method(mh, CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
address Method::from_compiled_entry_no_trampoline() const {
|
||||
|
||||
@ -76,6 +76,7 @@ class Method : public Metadata {
|
||||
ConstMethod* _constMethod; // Method read-only data.
|
||||
MethodData* _method_data;
|
||||
MethodCounters* _method_counters;
|
||||
AdapterHandlerEntry* _adapter;
|
||||
AccessFlags _access_flags; // Access flags
|
||||
int _vtable_index; // vtable index of this method (see VtableIndexFlag)
|
||||
// note: can have vtables with >2**16 elements (because of inheritance)
|
||||
@ -464,13 +465,7 @@ private:
|
||||
public:
|
||||
static void set_code(const methodHandle& mh, CompiledMethod* code);
|
||||
void set_adapter_entry(AdapterHandlerEntry* adapter) {
|
||||
constMethod()->set_adapter_entry(adapter);
|
||||
}
|
||||
void set_adapter_trampoline(AdapterHandlerEntry** trampoline) {
|
||||
constMethod()->set_adapter_trampoline(trampoline);
|
||||
}
|
||||
void update_adapter_trampoline(AdapterHandlerEntry* adapter) {
|
||||
constMethod()->update_adapter_trampoline(adapter);
|
||||
_adapter = adapter;
|
||||
}
|
||||
void set_from_compiled_entry(address entry) {
|
||||
_from_compiled_entry = entry;
|
||||
@ -481,7 +476,7 @@ public:
|
||||
address get_c2i_unverified_entry();
|
||||
address get_c2i_no_clinit_check_entry();
|
||||
AdapterHandlerEntry* adapter() const {
|
||||
return constMethod()->adapter();
|
||||
return _adapter;
|
||||
}
|
||||
// setup entry points
|
||||
void link_method(const methodHandle& method, TRAPS);
|
||||
@ -516,8 +511,6 @@ public:
|
||||
address interpreter_entry() const { return _i2i_entry; }
|
||||
// Only used when first initialize so we can set _i2i_entry and _from_interpreted_entry
|
||||
void set_interpreter_entry(address entry) {
|
||||
assert(!is_shared(),
|
||||
"shared method's interpreter entry should not be changed at run time");
|
||||
if (_i2i_entry != entry) {
|
||||
_i2i_entry = entry;
|
||||
}
|
||||
|
||||
@ -2643,31 +2643,6 @@ AdapterHandlerEntry* AdapterHandlerLibrary::new_entry(AdapterFingerPrint* finger
|
||||
}
|
||||
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(const methodHandle& method) {
|
||||
AdapterHandlerEntry* entry = get_adapter0(method);
|
||||
if (entry != NULL && method->is_shared()) {
|
||||
// See comments around Method::link_method()
|
||||
MutexLocker mu(AdapterHandlerLibrary_lock);
|
||||
if (method->adapter() == NULL) {
|
||||
method->update_adapter_trampoline(entry);
|
||||
}
|
||||
address trampoline = method->from_compiled_entry();
|
||||
if (*(int*)trampoline == 0) {
|
||||
CodeBuffer buffer(trampoline, (int)SharedRuntime::trampoline_size());
|
||||
MacroAssembler _masm(&buffer);
|
||||
SharedRuntime::generate_trampoline(&_masm, entry->get_c2i_entry());
|
||||
assert(*(int*)trampoline != 0, "Instruction(s) for trampoline must not be encoded as zeros.");
|
||||
_masm.flush();
|
||||
|
||||
if (PrintInterpreter) {
|
||||
Disassembler::decode(buffer.insts_begin(), buffer.insts_end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter0(const methodHandle& method) {
|
||||
// Use customized signature handler. Need to lock around updates to
|
||||
// the AdapterHandlerTable (it is not safe for concurrent readers
|
||||
// and a single writer: this could be fixed if it becomes a
|
||||
|
||||
@ -390,8 +390,6 @@ class SharedRuntime: AllStatic {
|
||||
|
||||
static size_t trampoline_size();
|
||||
|
||||
static void generate_trampoline(MacroAssembler *masm, address destination);
|
||||
|
||||
// Generate I2C and C2I adapters. These adapters are simple argument marshalling
|
||||
// blobs. Unlike adapters in the tiger and earlier releases the code in these
|
||||
// blobs does not create a new frame and are therefore virtually invisible
|
||||
@ -695,7 +693,6 @@ class AdapterHandlerLibrary: public AllStatic {
|
||||
static AdapterHandlerEntry* _abstract_method_handler;
|
||||
static BufferBlob* buffer_blob();
|
||||
static void initialize();
|
||||
static AdapterHandlerEntry* get_adapter0(const methodHandle& method);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2021, 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
|
||||
@ -37,11 +37,11 @@ public class FileMapInfo {
|
||||
private static FileMapHeader headerObj;
|
||||
|
||||
// Fields for handling the copied C++ vtables
|
||||
private static Address mcRegionBaseAddress;
|
||||
private static Address mcRegionEndAddress;
|
||||
private static Address rwRegionBaseAddress;
|
||||
private static Address rwRegionEndAddress;
|
||||
private static Address vtablesIndex;
|
||||
|
||||
// HashMap created by mapping the vTable addresses in the mc region with
|
||||
// HashMap created by mapping the vTable addresses in the rw region with
|
||||
// the corresponding metadata type.
|
||||
private static Map<Address, Type> vTableTypeMap;
|
||||
|
||||
@ -100,14 +100,14 @@ public class FileMapInfo {
|
||||
long cloned_vtable_offset = get_CIntegerField(FileMapHeader_type, header, "_cloned_vtables_offset");
|
||||
vtablesIndex = mapped_base_address.addOffsetTo(cloned_vtable_offset);
|
||||
|
||||
// CDSFileMapRegion* mc_space = &header->_space[mc];
|
||||
// char* mcRegionBaseAddress = mc_space->_mapped_base;
|
||||
// size_t used = mc_space->_used;
|
||||
// char* mcRegionEndAddress = mcRegionBaseAddress + used;
|
||||
Address mc_space = get_CDSFileMapRegion(FileMapHeader_type, header, 0);
|
||||
mcRegionBaseAddress = get_AddressField(CDSFileMapRegion_type, mc_space, "_mapped_base");
|
||||
long used = get_CIntegerField(CDSFileMapRegion_type, mc_space, "_used");
|
||||
mcRegionEndAddress = mcRegionBaseAddress.addOffsetTo(used);
|
||||
// CDSFileMapRegion* rw_space = &header->_space[rw];
|
||||
// char* rwRegionBaseAddress = rw_space->_mapped_base;
|
||||
// size_t used = rw_space->_used;
|
||||
// char* rwRegionEndAddress = rwRegionBaseAddress + used;
|
||||
Address rw_space = get_CDSFileMapRegion(FileMapHeader_type, header, 0);
|
||||
rwRegionBaseAddress = get_AddressField(CDSFileMapRegion_type, rw_space, "_mapped_base");
|
||||
long used = get_CIntegerField(CDSFileMapRegion_type, rw_space, "_used");
|
||||
rwRegionEndAddress = rwRegionBaseAddress.addOffsetTo(used);
|
||||
|
||||
populateMetadataTypeArray(db);
|
||||
}
|
||||
@ -154,8 +154,8 @@ public class FileMapInfo {
|
||||
if (vptrAddress == null) {
|
||||
return false;
|
||||
}
|
||||
if (vptrAddress.greaterThan(mcRegionBaseAddress) &&
|
||||
vptrAddress.lessThanOrEqual(mcRegionEndAddress)) {
|
||||
if (vptrAddress.greaterThan(rwRegionBaseAddress) &&
|
||||
vptrAddress.lessThanOrEqual(rwRegionEndAddress)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@ -43,7 +43,7 @@ import java.util.Hashtable;
|
||||
import java.lang.Integer;
|
||||
|
||||
public class SpaceUtilizationCheck {
|
||||
// For the MC/RW/RO regions:
|
||||
// For the RW/RO regions:
|
||||
// [1] Each region must have strictly less than
|
||||
// WhiteBox.metaspaceReserveAlignment() bytes of unused space.
|
||||
// [2] There must be no gap between two consecutive regions.
|
||||
@ -61,9 +61,8 @@ public class SpaceUtilizationCheck {
|
||||
long reserve_alignment = wb.metaspaceReserveAlignment();
|
||||
System.out.println("Metaspace::reserve_alignment() = " + reserve_alignment);
|
||||
|
||||
// Look for output like this. The pattern will only match the first 3 regions, which is what we need to check
|
||||
// Look for output like this. The pattern will only match the first 2 regions, which is what we need to check
|
||||
//
|
||||
// [4.682s][debug][cds] mc space: 24912 [ 0.2% of total] out of 28672 bytes [ 86.9% used] at 0x0000000800000000
|
||||
// [4.682s][debug][cds] rw space: 4391632 [ 33.7% of total] out of 4395008 bytes [ 99.9% used] at 0x0000000800007000
|
||||
// [4.682s][debug][cds] ro space: 7570632 [ 58.0% of total] out of 7573504 bytes [100.0% used] at 0x0000000800438000
|
||||
// [4.682s][debug][cds] bm space: 213528 [ 1.6% of total] out of 213528 bytes [100.0% used]
|
||||
@ -100,8 +99,8 @@ public class SpaceUtilizationCheck {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (checked.size() != 3) {
|
||||
throw new RuntimeException("Must have 3 consecutive, fully utilized regions"); // MC,RW,RO
|
||||
if (checked.size() != 2) {
|
||||
throw new RuntimeException("Must have 2 consecutive, fully utilized regions"); // RW,RO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,7 +70,6 @@ public class SharedArchiveConsistency {
|
||||
|
||||
// The following should be consistent with the enum in the C++ MetaspaceShared class
|
||||
public static String[] shared_region_name = {
|
||||
"mc", // MiscCode
|
||||
"rw", // ReadWrite
|
||||
"ro", // ReadOnly
|
||||
"bm", // relocation bitmaps
|
||||
|
||||
@ -49,7 +49,7 @@ import sun.hotspot.WhiteBox;
|
||||
public class ArchiveConsistency extends DynamicArchiveTestBase {
|
||||
public static WhiteBox wb;
|
||||
public static int int_size; // size of int
|
||||
public static String[] shared_region_name = {"MiscCode", "ReadWrite", "ReadOnly", "BitMap"};
|
||||
public static String[] shared_region_name = {"ReadWrite", "ReadOnly", "BitMap"};
|
||||
public static int num_regions = shared_region_name.length;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
@ -117,7 +117,7 @@ public class ArchiveConsistency extends DynamicArchiveTestBase {
|
||||
int baseArchiveCRCOffset = wb.getOffsetForName("DynamicArchiveHeader::_base_region_crc");
|
||||
int crc = 0;
|
||||
System.out.printf("%-12s%-12s\n", "Space name", "CRC");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int i = 0; i < num_regions; i++) {
|
||||
baseArchiveCRCOffset += int_size * i;
|
||||
System.out.println(" baseArchiveCRCOffset " + baseArchiveCRCOffset);
|
||||
crc = (int)readInt(fc, baseArchiveCRCOffset, int_size );
|
||||
|
||||
@ -92,7 +92,7 @@ public class DynamicArchiveRelocationTest extends DynamicArchiveTestBase {
|
||||
String unmapPattern = unmapPrefix + "(Bitmap)";
|
||||
String archiveRelocPattern = ".*ArchiveRelocationMode == 1.*";
|
||||
String unmapRgn1Pattern = ".*Unmapping region #1 at base 0x.*";
|
||||
String unmapRgn0Pattern = ".*Unmapping region #0 at base 0x.*(MiscCode)";
|
||||
String unmapRgn0Pattern = ".*Unmapping region #0 at base 0x.*(ReadWrite)";
|
||||
String unlockArg = "-XX:+UnlockDiagnosticVMOptions";
|
||||
|
||||
// (1) Dump base archive (static)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user