Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8243506: SharedBaseAddress is ignored by -Xshare:dump
Reviewed-by: stuefe, ccheung
  • Loading branch information
iklam committed Jun 2, 2020
1 parent b5775c8 commit f39a71cafec8dc9fca0b7bb10ea3a2f6c2fbcf36
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2020, 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
@@ -31,6 +31,7 @@
#include "memory/heapShared.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
#include "runtime/globals.hpp"
#include "runtime/vmThread.hpp"
#include "utilities/numberSeq.hpp"
#include <sys/stat.h>
@@ -212,11 +213,13 @@ size_t SimpleCompactHashtable::calculate_header_size() {
void SimpleCompactHashtable::serialize_header(SerializeClosure* soc) {
// NOTE: if you change this function, you MUST change the number 5 in
// calculate_header_size() accordingly.
soc->do_ptr((void**)&_base_address);
soc->do_u4(&_entry_count);
soc->do_u4(&_bucket_count);
soc->do_ptr((void**)&_buckets);
soc->do_ptr((void**)&_entries);
if (soc->reading()) {
_base_address = (address)SharedBaseAddress;
}
}
#endif // INCLUDE_CDS

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, 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
@@ -58,6 +58,12 @@ void ArchivePtrMarker::mark_pointer(address* ptr_loc) {

if (_ptr_base <= ptr_loc && ptr_loc < _ptr_end) {
address value = *ptr_loc;
// We don't want any pointer that points to very bottom of the archive, otherwise when
// MetaspaceShared::default_base_address()==0, we can't distinguish between a pointer
// to nothing (NULL) vs a pointer to an objects that happens to be at the very bottom
// of the archive.
assert(value != (address)_ptr_base, "don't point to the bottom of the archive");

if (value != NULL) {
assert(uintx(ptr_loc) % sizeof(intptr_t) == 0, "pointers must be stored in aligned addresses");
size_t idx = ptr_loc - _ptr_base;
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, 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
@@ -52,6 +52,7 @@ inline bool SharedDataRelocator<COMPACTING>::do_bit(size_t offset) {
}

address new_ptr = old_ptr + _delta;
assert(new_ptr != NULL, "don't point to the bottom of the archive"); // See ArchivePtrMarker::mark_pointer().
assert(_valid_new_base <= new_ptr && new_ptr < _valid_new_end, "must be");

DEBUG_ONLY(log_trace(cds, reloc)("Patch2: @%8d [" PTR_FORMAT "] " PTR_FORMAT " -> " PTR_FORMAT,
@@ -966,13 +966,13 @@ void DynamicArchiveBuilder::relocate_buffer_to_target() {
if (addr_delta == 0) {
ArchivePtrMarker::compact(relocatable_base, relocatable_end);
} else {
// The base archive is NOT mapped at Arguments::default_SharedBaseAddress() (due to ASLR).
// The base archive is NOT mapped at MetaspaceShared::requested_base_address() (due to ASLR).
// This means that the current content of the dynamic archive is based on a random
// address. Let's relocate all the pointers, so that it can be mapped to
// Arguments::default_SharedBaseAddress() without runtime relocation.
// MetaspaceShared::requested_base_address() without runtime relocation.
//
// Note: both the base and dynamic archive are written with
// FileMapHeader::_shared_base_address == Arguments::default_SharedBaseAddress()
// FileMapHeader::_requested_base_address == MetaspaceShared::requested_base_address()

// Patch all pointers that are marked by ptrmap within this region,
// where we have just dumped all the metaspace data.
@@ -992,7 +992,7 @@ void DynamicArchiveBuilder::relocate_buffer_to_target() {

// after patching, the pointers must point inside this range
// (the requested location of the archive, as mapped at runtime).
address valid_new_base = (address)Arguments::default_SharedBaseAddress();
address valid_new_base = (address)MetaspaceShared::requested_base_address();
address valid_new_end = valid_new_base + base_plus_top_size;

log_debug(cds)("Relocating archive from [" INTPTR_FORMAT " - " INTPTR_FORMAT "] to "
@@ -1020,7 +1020,7 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data) {
const char* archive_name = Arguments::GetSharedDynamicArchivePath();
dynamic_info->open_for_write(archive_name);
MetaspaceShared::write_core_archive_regions(dynamic_info, NULL, NULL);
dynamic_info->set_final_requested_base((char*)Arguments::default_SharedBaseAddress());
dynamic_info->set_final_requested_base((char*)MetaspaceShared::requested_base_address());
dynamic_info->set_header_crc(dynamic_info->compute_header_crc());
dynamic_info->write_header();
dynamic_info->close();
@@ -88,6 +88,7 @@ address MetaspaceShared::_i2i_entry_code_buffers = NULL;
size_t MetaspaceShared::_i2i_entry_code_buffers_size = 0;
void* MetaspaceShared::_shared_metaspace_static_top = NULL;
intx MetaspaceShared::_relocation_delta;
char* MetaspaceShared::_requested_base_address;

// The CDS archive is divided into the following regions:
// mc - misc code (the method entry trampolines, c++ vtables)
@@ -240,33 +241,53 @@ char* MetaspaceShared::read_only_space_alloc(size_t num_bytes) {

size_t MetaspaceShared::reserved_space_alignment() { return os::vm_allocation_granularity(); }

static bool shared_base_valid(char* shared_base) {
#ifdef _LP64
// Check SharedBaseAddress for validity. At this point, os::init() must
// have been ran.
static void check_SharedBaseAddress() {
SharedBaseAddress = align_up(SharedBaseAddress,
MetaspaceShared::reserved_space_alignment());
if (!CompressedKlassPointers::is_valid_base((address)SharedBaseAddress)) {
log_warning(cds)("SharedBaseAddress=" PTR_FORMAT " is invalid for this "
"platform, option will be ignored.",
p2i((address)SharedBaseAddress));
return CompressedKlassPointers::is_valid_base((address)shared_base);
#else
return true;
#endif
}

static bool shared_base_too_high(char* shared_base, size_t cds_total) {
if (SharedBaseAddress != 0 && shared_base < (char*)SharedBaseAddress) {
// SharedBaseAddress is very high (e.g., 0xffffffffffffff00) so
// align_up(SharedBaseAddress, MetaspaceShared::reserved_space_alignment()) has wrapped around.
return true;
}
if (max_uintx - uintx(shared_base) < uintx(cds_total)) {
// The end of the archive will wrap around
return true;
}

return false;
}

static char* compute_shared_base(size_t cds_total) {
char* shared_base = (char*)align_up((char*)SharedBaseAddress, MetaspaceShared::reserved_space_alignment());
const char* err = NULL;
if (shared_base_too_high(shared_base, cds_total)) {
err = "too high";
} else if (!shared_base_valid(shared_base)) {
err = "invalid for this platform";
}
if (err) {
log_warning(cds)("SharedBaseAddress (" INTPTR_FORMAT ") is %s. Reverted to " INTPTR_FORMAT,
p2i((void*)SharedBaseAddress), err,
p2i((void*)Arguments::default_SharedBaseAddress()));
SharedBaseAddress = Arguments::default_SharedBaseAddress();
shared_base = (char*)align_up((char*)SharedBaseAddress, MetaspaceShared::reserved_space_alignment());
}
assert(!shared_base_too_high(shared_base, cds_total) && shared_base_valid(shared_base), "Sanity");
return shared_base;
}
#endif

void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() {
assert(DumpSharedSpaces, "should be called for dump time only");

#ifdef _LP64
check_SharedBaseAddress();
#endif

const size_t reserve_alignment = MetaspaceShared::reserved_space_alignment();
char* shared_base = (char*)align_up((char*)SharedBaseAddress, reserve_alignment);

#ifdef _LP64
assert(CompressedKlassPointers::is_valid_base((address)shared_base), "Sanity");
// On 64-bit VM we reserve a 4G range and, if UseCompressedClassPointers=1,
// will use that to house both the archives and the ccs. See below for
// details.
@@ -278,6 +299,9 @@ void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() {
size_t cds_total = align_down(256*M, reserve_alignment);
#endif

char* shared_base = compute_shared_base(cds_total);
_requested_base_address = shared_base;

// Whether to use SharedBaseAddress as attach address.
bool use_requested_base = true;

@@ -398,6 +422,10 @@ void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() {
log_info(cds)("Allocated shared space: " SIZE_FORMAT " bytes at " PTR_FORMAT,
_shared_rs.size(), p2i(_shared_rs.base()));

// We don't want any valid object to be at the very bottom of the archive.
// See ArchivePtrMarker::mark_pointer().
MetaspaceShared::misc_code_space_alloc(16);

size_t symbol_rs_size = LP64_ONLY(3 * G) NOT_LP64(128 * M);
_symbol_rs = ReservedSpace(symbol_rs_size);
if (!_symbol_rs.is_reserved()) {
@@ -1200,7 +1228,7 @@ class VM_PopulateDumpSharedSpace: public VM_Operation {
void print_bitmap_region_stats(size_t size, size_t total_size);
void print_heap_region_stats(GrowableArray<MemRegion> *heap_mem,
const char *name, size_t total_size);
void relocate_to_default_base_address(CHeapBitMap* ptrmap);
void relocate_to_requested_base_address(CHeapBitMap* ptrmap);

public:

@@ -1568,18 +1596,18 @@ void VM_PopulateDumpSharedSpace::print_class_stats() {
}
}

void VM_PopulateDumpSharedSpace::relocate_to_default_base_address(CHeapBitMap* ptrmap) {
void VM_PopulateDumpSharedSpace::relocate_to_requested_base_address(CHeapBitMap* ptrmap) {
intx addr_delta = MetaspaceShared::final_delta();
if (addr_delta == 0) {
ArchivePtrMarker::compact((address)SharedBaseAddress, (address)_ro_region.top());
} else {
// We are not able to reserve space at Arguments::default_SharedBaseAddress() (due to ASLR).
// We are not able to reserve space at MetaspaceShared::requested_base_address() (due to ASLR).
// This means that the current content of the archive is based on a random
// address. Let's relocate all the pointers, so that it can be mapped to
// Arguments::default_SharedBaseAddress() without runtime relocation.
// MetaspaceShared::requested_base_address() without runtime relocation.
//
// Note: both the base and dynamic archive are written with
// FileMapHeader::_shared_base_address == Arguments::default_SharedBaseAddress()
// FileMapHeader::_requested_base_address == MetaspaceShared::requested_base_address()

// Patch all pointers that are marked by ptrmap within this region,
// where we have just dumped all the metaspace data.
@@ -1594,7 +1622,7 @@ void VM_PopulateDumpSharedSpace::relocate_to_default_base_address(CHeapBitMap* p

// after patching, the pointers must point inside this range
// (the requested location of the archive, as mapped at runtime).
address valid_new_base = (address)Arguments::default_SharedBaseAddress();
address valid_new_base = (address)MetaspaceShared::requested_base_address();
address valid_new_end = valid_new_base + size;

log_debug(cds)("Relocating archive from [" INTPTR_FORMAT " - " INTPTR_FORMAT " ] to "
@@ -1681,9 +1709,9 @@ void VM_PopulateDumpSharedSpace::doit() {
memset(MetaspaceShared::i2i_entry_code_buffers(), 0,
MetaspaceShared::i2i_entry_code_buffers_size());

// relocate the data so that it can be mapped to Arguments::default_SharedBaseAddress()
// relocate the data so that it can be mapped to MetaspaceShared::requested_base_address()
// without runtime relocation.
relocate_to_default_base_address(&ptrmap);
relocate_to_requested_base_address(&ptrmap);

// Create and write the archive file that maps the shared spaces.

@@ -1706,7 +1734,7 @@ void VM_PopulateDumpSharedSpace::doit() {
MetaspaceShared::first_open_archive_heap_region,
MetaspaceShared::max_open_archive_heap_region);

mapinfo->set_final_requested_base((char*)Arguments::default_SharedBaseAddress());
mapinfo->set_final_requested_base((char*)MetaspaceShared::requested_base_address());
mapinfo->set_header_crc(mapinfo->compute_header_crc());
mapinfo->write_header();
print_region_stats(mapinfo);
@@ -2162,6 +2190,7 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
} else {
FileMapInfo::set_shared_path_table(static_mapinfo);
}
_requested_base_address = static_mapinfo->requested_base_address();
} else {
set_shared_metaspace_range(NULL, NULL, NULL);
UseSharedSpaces = false;
@@ -2209,6 +2238,11 @@ FileMapInfo* MetaspaceShared::open_dynamic_archive() {
// false = map at an alternative address picked by OS.
MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo,
bool use_requested_addr) {
if (use_requested_addr && static_mapinfo->requested_base_address() == NULL) {
log_info(cds)("Archive(s) were created with -XX:SharedBaseAddress=0. Always map at os-selected address.");
return MAP_ARCHIVE_MMAP_FAILURE;
}

PRODUCT_ONLY(if (ArchiveRelocationMode == 1 && use_requested_addr) {
// For product build only -- this is for benchmarking the cost of doing relocation.
// For debug builds, the check is done below, after reserving the space, for better test coverage
@@ -2660,11 +2694,11 @@ void MetaspaceShared::report_out_of_space(const char* name, size_t needed_bytes)
"Please reduce the number of shared classes.");
}

// This is used to relocate the pointers so that the archive can be mapped at
// Arguments::default_SharedBaseAddress() without runtime relocation.
// This is used to relocate the pointers so that the base archive can be mapped at
// MetaspaceShared::requested_base_address() without runtime relocation.
intx MetaspaceShared::final_delta() {
return intx(Arguments::default_SharedBaseAddress()) // We want the archive to be mapped to here at runtime
- intx(SharedBaseAddress); // .. but the archive is mapped at here at dump time
return intx(MetaspaceShared::requested_base_address()) // We want the base archive to be mapped to here at runtime
- intx(SharedBaseAddress); // .. but the base archive is mapped at here at dump time
}

void MetaspaceShared::print_on(outputStream* st) {
@@ -183,6 +183,7 @@ class MetaspaceShared : AllStatic {
static size_t _core_spaces_size;
static void* _shared_metaspace_static_top;
static intx _relocation_delta;
static char* _requested_base_address;
public:
enum {
// core archive spaces
@@ -353,6 +354,12 @@ class MetaspaceShared : AllStatic {
static intptr_t* fix_cpp_vtable_for_dynamic_archive(MetaspaceObj::Type msotype, address obj);
static void initialize_ptr_marker(CHeapBitMap* ptrmap);

// 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.
static char* requested_base_address() {
return _requested_base_address;
}

// Non-zero if the archive(s) need to be mapped a non-default location due to ASLR.
static intx relocation_delta() { return _relocation_delta; }
static intx final_delta();
@@ -85,7 +85,7 @@ bool Arguments::_BackgroundCompilation = BackgroundCompilation;
bool Arguments::_ClipInlining = ClipInlining;
intx Arguments::_Tier3InvokeNotifyFreqLog = Tier3InvokeNotifyFreqLog;
intx Arguments::_Tier4InvocationThreshold = Tier4InvocationThreshold;
size_t Arguments::_SharedBaseAddress = SharedBaseAddress;
size_t Arguments::_default_SharedBaseAddress = SharedBaseAddress;

bool Arguments::_enable_preview = false;

@@ -2281,8 +2281,8 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *vm_options_args,
Arguments::_Tier4InvocationThreshold = Tier4InvocationThreshold;
}

// CDS dumping always write the archive to the default value of SharedBaseAddress.
Arguments::_SharedBaseAddress = SharedBaseAddress;
// Remember the default value of SharedBaseAddress.
Arguments::_default_SharedBaseAddress = SharedBaseAddress;

// Setup flags for mixed which is the default
set_mode_flags(_mixed);
@@ -489,7 +489,7 @@ class Arguments : AllStatic {

static char* SharedArchivePath;
static char* SharedDynamicArchivePath;
static size_t _SharedBaseAddress; // The default value specified in globals.hpp
static size_t _default_SharedBaseAddress; // The default value specified in globals.hpp
static int num_archives(const char* archive_path) NOT_CDS_RETURN_(0);
static void extract_shared_archive_paths(const char* archive_path,
char** base_archive_path,
@@ -572,7 +572,7 @@ class Arguments : AllStatic {

static const char* GetSharedArchivePath() { return SharedArchivePath; }
static const char* GetSharedDynamicArchivePath() { return SharedDynamicArchivePath; }
static size_t default_SharedBaseAddress() { return _SharedBaseAddress; }
static size_t default_SharedBaseAddress() { return _default_SharedBaseAddress; }
// Java launcher properties
static void process_sun_java_launcher_properties(JavaVMInitArgs* args);

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, 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
@@ -40,7 +40,13 @@ public class SharedBaseAddress {
private static final String[] testTable = {
"1g", "8g", "64g","512g", "4t",
"32t", "128t", "0",
"1", "64k", "64M"
"1", "64k", "64M",
"0xfffffffffff00000", // archive top wraps around 64-bit address space
"0xfff80000", // archive top wraps around 32-bit address space
"0xffffffffffffffff", // archive bottom wraps around 64-bit address space -- due to align_up()
"0xffffffff", // archive bottom wraps around 32-bit address space -- due to align_up()
"0x00007ffffff00000", // end of archive will go past the end of user space on linux/x64
"0", // always let OS pick the base address at runtime (ASLR for CDS archive)
};

public static void main(String[] args) throws Exception {
@@ -50,10 +56,16 @@ public static void main(String[] args) throws Exception {
System.out.println("sharedBaseAddress = " + testEntry);
CDSOptions opts = (new CDSOptions())
.setArchiveName(filename)
.addPrefix("-XX:SharedBaseAddress=" + testEntry);
.addPrefix("-XX:SharedBaseAddress=" + testEntry)
.addPrefix("-Xlog:cds=debug")
.addPrefix("-Xlog:cds+reloc=debug");

CDSTestUtils.createArchiveAndCheck(opts);
CDSTestUtils.runWithArchiveAndCheck(opts);
OutputAnalyzer out = CDSTestUtils.runWithArchiveAndCheck(opts);
if (testEntry.equals("0")) {
out.shouldContain("Archive(s) were created with -XX:SharedBaseAddress=0. Always map at os-selected address.")
.shouldContain("Try to map archive(s) at an alternative address");
}
}
}
}

0 comments on commit f39a71c

Please sign in to comment.