--- old/src/hotspot/share/classfile/compactHashtable.cpp 2020-05-05 11:14:47.421020208 -0700 +++ new/src/hotspot/share/classfile/compactHashtable.cpp 2020-05-05 11:14:47.301015691 -0700 @@ -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 @@ -212,11 +213,13 @@ 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 --- old/src/hotspot/share/memory/archiveUtils.cpp 2020-05-05 11:14:47.933039481 -0700 +++ new/src/hotspot/share/memory/archiveUtils.cpp 2020-05-05 11:14:47.813034964 -0700 @@ -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 @@ 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; --- old/src/hotspot/share/memory/archiveUtils.inline.hpp 2020-05-05 11:14:48.441058604 -0700 +++ new/src/hotspot/share/memory/archiveUtils.inline.hpp 2020-05-05 11:14:48.321054087 -0700 @@ -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 @@ } 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, --- old/src/hotspot/share/memory/dynamicArchive.cpp 2020-05-05 11:14:48.937077275 -0700 +++ new/src/hotspot/share/memory/dynamicArchive.cpp 2020-05-05 11:14:48.813072607 -0700 @@ -967,13 +967,13 @@ 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::default_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::default_base_address() without runtime relocation. // // Note: both the base and dynamic archive are written with - // FileMapHeader::_shared_base_address == Arguments::default_SharedBaseAddress() + // FileMapHeader::_shared_base_address == MetaspaceShared::default_base_address() // Patch all pointers that are marked by ptrmap within this region, // where we have just dumped all the metaspace data. @@ -993,7 +993,7 @@ // 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::default_base_address(); address valid_new_end = valid_new_base + base_plus_top_size; log_debug(cds)("Relocating archive from [" INTPTR_FORMAT " - " INTPTR_FORMAT "] to " @@ -1021,7 +1021,7 @@ 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::default_base_address()); dynamic_info->set_header_crc(dynamic_info->compute_header_crc()); dynamic_info->write_header(); dynamic_info->close(); --- old/src/hotspot/share/memory/metaspaceShared.cpp 2020-05-05 11:14:49.457096849 -0700 +++ new/src/hotspot/share/memory/metaspaceShared.cpp 2020-05-05 11:14:49.337092332 -0700 @@ -85,6 +85,7 @@ size_t MetaspaceShared::_i2i_entry_code_buffers_size = 0; void* MetaspaceShared::_shared_metaspace_static_top = NULL; intx MetaspaceShared::_relocation_delta; +char* MetaspaceShared::_default_base_address; // The CDS archive is divided into the following regions: // mc - misc code (the method entry trampolines, c++ vtables) @@ -244,7 +245,6 @@ void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() { assert(DumpSharedSpaces, "should be called for dump time only"); const size_t reserve_alignment = reserved_space_alignment(); - char* shared_base = (char*)align_up((char*)SharedBaseAddress, reserve_alignment); #ifdef _LP64 // On 64-bit VM, the heap and class space layout will be the same as if @@ -264,6 +264,18 @@ size_t cds_total = align_down(256*M, reserve_alignment); #endif + char* shared_base = (char*)align_up((char*)SharedBaseAddress, reserve_alignment); + if ((shared_base == NULL && SharedBaseAddress != 0) // align_up has wrapped around + || (max_uintx - uintx(shared_base) < uintx(cds_total))) { // end of the archive will wrap around + log_warning(cds)("SharedBaseAddress (" INTPTR_FORMAT ") is too high. Reverted to " INTPTR_FORMAT, + p2i((void*)SharedBaseAddress), + p2i((void*)Arguments::default_SharedBaseAddress())); + SharedBaseAddress = Arguments::default_SharedBaseAddress(); + shared_base = (char*)align_up((char*)SharedBaseAddress, reserve_alignment); + assert(uintx(shared_base + cds_total) > uintx(shared_base), "must not wrap around"); + } + _default_base_address = shared_base; + bool use_requested_base = true; if (ArchiveRelocationMode == 1) { log_info(cds)("ArchiveRelocationMode == 1: always allocate class space at an alternative address"); @@ -320,6 +332,10 @@ SharedBaseAddress = (size_t)_shared_rs.base(); 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 of the archive. + // See ArchivePtrMarker::mark_pointer(). + MetaspaceShared::misc_code_space_alloc(16); } // Called by universe_post_init() @@ -1456,13 +1472,13 @@ 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::default_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::default_base_address() without runtime relocation. // // Note: both the base and dynamic archive are written with - // FileMapHeader::_shared_base_address == Arguments::default_SharedBaseAddress() + // FileMapHeader::_shared_base_address == MetaspaceShared::default_base_address() // Patch all pointers that are marked by ptrmap within this region, // where we have just dumped all the metaspace data. @@ -1477,7 +1493,7 @@ // 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::default_base_address(); address valid_new_end = valid_new_base + size; log_debug(cds)("Relocating archive from [" INTPTR_FORMAT " - " INTPTR_FORMAT " ] to " @@ -1561,7 +1577,7 @@ // We don't want to write these addresses into the archive. MetaspaceShared::zero_cpp_vtable_clones_for_writing(); - // relocate the data so that it can be mapped to Arguments::default_SharedBaseAddress() + // relocate the data so that it can be mapped to MetaspaceShared::default_base_address() // without runtime relocation. relocate_to_default_base_address(&ptrmap); @@ -1586,7 +1602,7 @@ 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::default_base_address()); mapinfo->set_header_crc(mapinfo->compute_header_crc()); mapinfo->write_header(); print_region_stats(mapinfo); @@ -2041,6 +2057,7 @@ } else { FileMapInfo::set_shared_path_table(static_mapinfo); } + _default_base_address = static_mapinfo->requested_base_address(); } else { set_shared_metaspace_range(NULL, NULL, NULL); UseSharedSpaces = false; @@ -2088,6 +2105,11 @@ // 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 in FileMapInfo::map_regions for better test coverage. @@ -2411,9 +2433,9 @@ "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::default_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::default_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 } --- old/src/hotspot/share/memory/metaspaceShared.hpp 2020-05-05 11:14:49.989116876 -0700 +++ new/src/hotspot/share/memory/metaspaceShared.hpp 2020-05-05 11:14:49.865112208 -0700 @@ -188,6 +188,7 @@ static size_t _core_spaces_size; static void* _shared_metaspace_static_top; static intx _relocation_delta; + static char* _default_base_address; public: enum { // core archive spaces @@ -350,6 +351,12 @@ 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* default_base_address() { + return _default_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(); --- old/src/hotspot/share/runtime/arguments.cpp 2020-05-05 11:14:50.501136149 -0700 +++ new/src/hotspot/share/runtime/arguments.cpp 2020-05-05 11:14:50.377131481 -0700 @@ -85,7 +85,7 @@ 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; @@ -2237,8 +2237,8 @@ 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); --- old/src/hotspot/share/runtime/arguments.hpp 2020-05-05 11:14:51.049156777 -0700 +++ new/src/hotspot/share/runtime/arguments.hpp 2020-05-05 11:14:50.921151959 -0700 @@ -481,7 +481,7 @@ 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, @@ -564,7 +564,7 @@ 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); --- old/test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java 2020-05-05 11:14:51.581176804 -0700 +++ new/test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java 2020-05-05 11:14:51.457172136 -0700 @@ -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,12 @@ 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 }; public static void main(String[] args) throws Exception { @@ -50,7 +55,9 @@ 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); --- /dev/null 2019-11-19 22:05:02.069813242 -0800 +++ new/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/SharedBaseAddressOption.java 2020-05-05 11:14:51.973191560 -0700 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @summary Test how the dynamic archive handles -XX:SharedBaseAddress + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @build Hello + * @run driver ClassFileInstaller -jar hello.jar Hello + * @run driver SharedBaseAddressOption + */ + +import jdk.test.lib.Platform; + +public class SharedBaseAddressOption extends DynamicArchiveTestBase { + static String appJar = ClassFileInstaller.getJarPath("hello.jar"); + static String mainClass = "Hello"; + + public static void main(String[] args) throws Exception { + runTest(SharedBaseAddressOption::testCustomBase); + } + + static void testCustomBase() throws Exception { + + // (1) -XX:SharedBaseAddress=0 -- the archives will always be relocated at runtime + doTest("0"); + + // (2) -XX:SharedBaseAddress=0x810000000 + if (Platform.is64bit()) { + doTest("0x810000000"); + } + + // (3) -XX:SharedBaseAddress that's so high that the archive may wrap around 64-bit + if (Platform.is64bit()) { + doTest("0xffffffffff000000"); + } + } + + static void doTest(String sharedBase) throws Exception { + String topArchiveName = getNewArchiveName("top"); + String baseArchiveName = getNewArchiveName("base"); + + dumpBaseArchive(topArchiveName, "-XX:SharedBaseAddress=" + sharedBase, + "-Xlog:cds=debug", + "-Xlog:cds+reloc=debug", + "-Xlog:cds+dynamic=debug"); + + dump2(topArchiveName, baseArchiveName, + "-Xlog:cds=debug", + "-Xlog:cds+reloc=debug", + "-Xlog:cds+dynamic=debug", + "-cp", appJar, mainClass) + .assertNormalExit(); + + // a top archive specified in the base archive position + run2(topArchiveName, baseArchiveName, + "-Xlog:cds=debug", + "-Xlog:cds+reloc=debug", + "-Xlog:cds+dynamic=debug", + "-cp", appJar, mainClass) + .assertNormalExit(); + } +}