8271569: Clean up the use of CDS constants and field offsets

Reviewed-by: iklam, dholmes
This commit is contained in:
Yumin Qi 2021-09-16 17:56:07 +00:00
parent 12fa7073c5
commit 9c5441c9c4
10 changed files with 187 additions and 143 deletions

@ -0,0 +1,71 @@
/*
* Copyright (c) 2014, 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
* 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.
*
*/
#include "precompiled.hpp"
#include "cds.h"
#include "cds/cdsConstants.hpp"
#include "cds/dynamicArchive.hpp"
#include "cds/filemap.hpp"
#include "utilities/globalDefinitions.hpp"
CDSConst CDSConstants::offsets[] = {
{ "CDSFileMapHeaderBase::_magic", offset_of(CDSFileMapHeaderBase, _magic) },
{ "CDSFileMapHeaderBase::_crc", offset_of(CDSFileMapHeaderBase, _crc) },
{ "CDSFileMapHeaderBase::_version", offset_of(CDSFileMapHeaderBase, _version) },
{ "CDSFileMapHeaderBase::_space[0]", offset_of(CDSFileMapHeaderBase, _space) },
{ "FileMapHeader::_jvm_ident", offset_of(FileMapHeader, _jvm_ident) },
{ "FileMapHeader::_base_archive_name_size", offset_of(FileMapHeader, _base_archive_name_size) },
{ "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc) },
{ "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used) },
{ "DynamicArchiveHeader::_base_region_crc", offset_of(DynamicArchiveHeader, _base_region_crc) }
};
CDSConst CDSConstants::constants[] = {
{ "static_magic", (size_t)CDS_ARCHIVE_MAGIC },
{ "dynamic_magic", (size_t)CDS_DYNAMIC_ARCHIVE_MAGIC },
{ "int_size", sizeof(int) },
{ "CDSFileMapRegion_size", sizeof(CDSFileMapRegion) },
{ "static_file_header_size", sizeof(FileMapHeader) },
{ "dynamic_archive_header_size", sizeof(DynamicArchiveHeader) },
{ "size_t_size", sizeof(size_t) }
};
size_t CDSConstants::get_cds_offset(const char* name) {
for (int i = 0; i < (int)ARRAY_SIZE(offsets); i++) {
if (strcmp(name, offsets[i]._name) == 0) {
return offsets[i]._value;
}
}
return -1;
}
size_t CDSConstants::get_cds_constant(const char* name) {
for (int i = 0; i < (int)ARRAY_SIZE(constants); i++) {
if (strcmp(name, constants[i]._name) == 0) {
return constants[i]._value;
}
}
return -1;
}

@ -22,26 +22,22 @@
*
*/
#ifndef SHARE_CDS_CDSOFFSETS_HPP
#define SHARE_CDS_CDSOFFSETS_HPP
#ifndef SHARE_CDS_CDSCONSTANTS_HPP
#define SHARE_CDS_CDSCONSTANTS_HPP
#include "memory/allocation.hpp"
#include "memory/allStatic.hpp"
class CDSOffsets: public CHeapObj<mtInternal> {
typedef struct {
const char* _name;
size_t _value;
} CDSConst;
class CDSConstants : AllStatic {
private:
char* _name;
int _offset;
CDSOffsets* _next;
static CDSOffsets* _all; // sole list for cds
static CDSConst offsets[];
static CDSConst constants[];
public:
CDSOffsets(const char* name, int offset, CDSOffsets* next);
char* get_name() const { return _name; }
int get_offset() const { return _offset; }
CDSOffsets* next() const { return _next; }
void add_end(CDSOffsets* n);
static int find_offset(const char* name);
static size_t get_cds_constant(const char* name);
static size_t get_cds_offset(const char* name);
};
#endif // SHARE_CDS_CDSOFFSETS_HPP
#endif // SHARE_CDS_CDSCONSTANTS_HPP

@ -1,77 +0,0 @@
/*
* Copyright (c) 2014, 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
* 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.
*
*/
#include "precompiled.hpp"
#include "cds/cdsoffsets.hpp"
#include "cds/dynamicArchive.hpp"
#include "cds/filemap.hpp"
#include "runtime/os.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "utilities/macros.hpp"
CDSOffsets::CDSOffsets(const char* name, int offset, CDSOffsets* next) {
_name = NEW_C_HEAP_ARRAY(char, strlen(name) + 1, mtInternal);
strcpy(_name, name);
_offset = offset;
_next = next;
}
CDSOffsets* CDSOffsets::_all = NULL;
#define ADD_NEXT(list, name, value) \
list->add_end(new CDSOffsets(name, value, NULL))
#define CREATE_OFFSET_MAPS \
_all = new CDSOffsets("size_t_size", sizeof(size_t), NULL); \
ADD_NEXT(_all, "int_size", sizeof(int)); \
ADD_NEXT(_all, "FileMapHeader::_magic", offset_of(FileMapHeader, _magic)); \
ADD_NEXT(_all, "FileMapHeader::_crc", offset_of(FileMapHeader, _crc)); \
ADD_NEXT(_all, "FileMapHeader::_version", offset_of(FileMapHeader, _version)); \
ADD_NEXT(_all, "FileMapHeader::_jvm_ident", offset_of(FileMapHeader, _jvm_ident)); \
ADD_NEXT(_all, "FileMapHeader::_space[0]", offset_of(FileMapHeader, _space)); \
ADD_NEXT(_all, "CDSFileMapRegion::_crc", offset_of(CDSFileMapRegion, _crc)); \
ADD_NEXT(_all, "CDSFileMapRegion::_used", offset_of(CDSFileMapRegion, _used)); \
ADD_NEXT(_all, "file_header_size", sizeof(FileMapHeader)); \
ADD_NEXT(_all, "DynamicArchiveHeader::_base_region_crc", offset_of(DynamicArchiveHeader, _base_region_crc)); \
ADD_NEXT(_all, "CDSFileMapRegion_size", sizeof(CDSFileMapRegion));
int CDSOffsets::find_offset(const char* name) {
if (_all == NULL) {
CREATE_OFFSET_MAPS
}
CDSOffsets* it = _all;
while(it) {
if (!strcmp(name, it->get_name())) {
return it->get_offset();
}
it = it->next();
}
return -1; // not found
}
void CDSOffsets::add_end(CDSOffsets* n) {
CDSOffsets* p = this;
while(p && p->_next) { p = p->_next; }
p->_next = n;
}

@ -38,7 +38,7 @@
#if INCLUDE_CDS
class DynamicArchiveHeader : public FileMapHeader {
friend class CDSOffsets;
friend class CDSConstants;
private:
int _base_header_crc;
int _base_region_crc[MetaspaceShared::n_regions];

@ -180,9 +180,10 @@ public:
};
class FileMapHeader: private CDSFileMapHeaderBase {
friend class CDSOffsets;
friend class CDSConstants;
friend class VMStructs;
private:
size_t _header_size;
// The following fields record the states of the VM during dump time.
@ -209,7 +210,6 @@ class FileMapHeader: private CDSFileMapHeaderBase {
// will function correctly with this JVM and the bootclasspath it's
// invoked with.
char _jvm_ident[JVM_IDENT_MAX]; // identifier string of the jvm that created this dump
// size of the base archive name including NULL terminator
size_t _base_archive_name_size;

@ -25,6 +25,8 @@
#ifndef SHARE_INCLUDE_CDS_H
#define SHARE_INCLUDE_CDS_H
#include <stddef.h>
// This file declares the CDS data structures that are used by the HotSpot Serviceability Agent
// (see C sources inside src/jdk.hotspot.agent).
//

@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include <new>
#include "cds/cdsoffsets.hpp"
#include "cds/cdsConstants.hpp"
#include "cds/filemap.hpp"
#include "cds/heapShared.inline.hpp"
#include "cds/metaspaceShared.hpp"
@ -2016,11 +2016,18 @@ WB_END
#if INCLUDE_CDS
WB_ENTRY(jint, WB_GetOffsetForName(JNIEnv* env, jobject o, jstring name))
WB_ENTRY(jint, WB_GetCDSOffsetForName(JNIEnv* env, jobject o, jstring name))
ResourceMark rm;
char* c_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(name));
int result = CDSOffsets::find_offset(c_name);
return (jint)result;
jint result = (jint)CDSConstants::get_cds_offset(c_name);
return result;
WB_END
WB_ENTRY(jint, WB_GetCDSConstantForName(JNIEnv* env, jobject o, jstring name))
ResourceMark rm;
char* c_name = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(name));
jint result = (jint)CDSConstants::get_cds_constant(c_name);
return result;
WB_END
#endif // INCLUDE_CDS
@ -2454,7 +2461,8 @@ static JNINativeMethod methods[] = {
{CC"readFromNoaccessArea",CC"()V", (void*)&WB_ReadFromNoaccessArea},
{CC"stressVirtualSpaceResize",CC"(JJJ)I", (void*)&WB_StressVirtualSpaceResize},
#if INCLUDE_CDS
{CC"getOffsetForName0", CC"(Ljava/lang/String;)I", (void*)&WB_GetOffsetForName},
{CC"getCDSOffsetForName0", CC"(Ljava/lang/String;)I", (void*)&WB_GetCDSOffsetForName},
{CC"getCDSConstantForName0", CC"(Ljava/lang/String;)I", (void*)&WB_GetCDSConstantForName},
#endif
#if INCLUDE_G1GC
{CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark},

@ -45,17 +45,23 @@ import sun.hotspot.WhiteBox;
// This class performs operations on shared archive file
public class CDSArchiveUtils {
public static int offsetMagic; // CDSFileMapHeaderBase::_magic
public static int offsetVersion; // CDSFileMapHeaderBase::_version
public static int offsetJvmIdent; // FileMapHeader::_jvm_ident
public static int spOffsetCrc; // CDSFileMapRegion::_crc
public static int fileHeaderSize; // total size of header, aligned with alignment
public static int cdsFileMapRegionSize; // size of CDSFileMapRegion
public static int spOffset; // offset of CDSFileMapRegion
public static int spUsedOffset; // offset of CDSFileMapRegion::_used
public static int sizetSize; // size of size_t
public static int intSize; // size of int
public static long alignment; // MetaspaceShared::core_region_alignment
// offsets
public static int offsetMagic; // CDSFileMapHeaderBase::_magic
public static int offsetVersion; // CDSFileMapHeaderBase::_version
public static int offsetJvmIdent; // FileMapHeader::_jvm_ident
public static int offsetBaseArchiveNameSize; // FileMapHeader::_base_archive_name_size
public static int spOffsetCrc; // CDSFileMapRegion::_crc
public static int spOffset; // offset of CDSFileMapRegion
public static int spUsedOffset; // offset of CDSFileMapRegion::_used
// constants
public static int staticMagic; // static magic value defined in hotspot
public static int dynamicMagic; // dyamic magic value defined in hotspot
public static int sizetSize; // size of size_t
public static int intSize; // size of int
public static int staticArchiveHeaderSize; // static archive file header size
public static int dynamicArchiveHeaderSize; // dynamic archive file header size
public static int cdsFileMapRegionSize; // size of CDSFileMapRegion
public static long alignment; // MetaspaceShared::core_region_alignment
// The following should be consistent with the enum in the C++ MetaspaceShared class
public static String[] shared_region_name = {
@ -73,31 +79,50 @@ public class CDSArchiveUtils {
WhiteBox wb;
try {
wb = WhiteBox.getWhiteBox();
offsetMagic = wb.getOffsetForName("FileMapHeader::_magic");
offsetVersion = wb.getOffsetForName("FileMapHeader::_version");
offsetJvmIdent = wb.getOffsetForName("FileMapHeader::_jvm_ident");
spOffsetCrc = wb.getOffsetForName("CDSFileMapRegion::_crc");
spOffset = wb.getOffsetForName("FileMapHeader::_space[0]") - offsetMagic;
spUsedOffset = wb.getOffsetForName("CDSFileMapRegion::_used") - spOffsetCrc;
sizetSize = wb.getOffsetForName("size_t_size");
intSize = wb.getOffsetForName("int_size");
cdsFileMapRegionSize = wb.getOffsetForName("CDSFileMapRegion_size");
// offsets
offsetMagic = wb.getCDSOffsetForName("CDSFileMapHeaderBase::_magic");
offsetVersion = wb.getCDSOffsetForName("CDSFileMapHeaderBase::_version");
offsetJvmIdent = wb.getCDSOffsetForName("FileMapHeader::_jvm_ident");
offsetBaseArchiveNameSize = wb.getCDSOffsetForName("FileMapHeader::_base_archive_name_size");
spOffsetCrc = wb.getCDSOffsetForName("CDSFileMapRegion::_crc");
spUsedOffset = wb.getCDSOffsetForName("CDSFileMapRegion::_used") - spOffsetCrc;
spOffset = wb.getCDSOffsetForName("CDSFileMapHeaderBase::_space[0]") - offsetMagic;
// constants
staticMagic = wb.getCDSConstantForName("static_magic");
dynamicMagic = wb.getCDSConstantForName("dynamic_magic");
staticArchiveHeaderSize = wb.getCDSConstantForName("static_file_header_size");
dynamicArchiveHeaderSize = wb.getCDSConstantForName("dynamic_archive_header_size");
sizetSize = wb.getCDSConstantForName("size_t_size");
intSize = wb.getCDSConstantForName("int_size");
cdsFileMapRegionSize = wb.getCDSConstantForName("CDSFileMapRegion_size");
alignment = wb.metaspaceSharedRegionAlignment();
// file_header_size is structure size, real size aligned with alignment
// so must be calculated after alignment is available
fileHeaderSize = (int)alignUpWithAlignment(wb.getOffsetForName("file_header_size"));
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
try {
int nonExistOffset = wb.getOffsetForName("FileMapHeader::_non_exist_offset");
int nonExistOffset = wb.getCDSOffsetForName("FileMapHeader::_non_exist_offset");
System.exit(-1); // should fail
} catch (Exception e) {
// success
}
}
public static long fileHeaderSize(File jsaFile) throws Exception {
long magicValue = readInt(jsaFile, offsetMagic, 4);
if (magicValue == staticMagic) {
return alignUpWithAlignment((long)staticArchiveHeaderSize);
} else if (magicValue == dynamicMagic) {
// dynamic archive store base archive name after header, so we count it in header size.
int baseArchiveNameSize = (int)readInt(jsaFile, (long)offsetBaseArchiveNameSize, 4);
return alignUpWithAlignment((long)dynamicArchiveHeaderSize + baseArchiveNameSize);
} else {
throw new RuntimeException("Wrong magic value from archive file: " + magicValue);
}
}
private static long alignUpWithAlignment(long l) {
return (l + alignment - 1) & (~ (alignment - 1));
}
@ -134,7 +159,7 @@ public class CDSArchiveUtils {
int bufSize;
System.out.printf("%-24s%12s%12s%16s\n", "Space Name", "Used bytes", "Reg Start", "Random Offset");
start0 = fileHeaderSize;
start0 = fileHeaderSize(jsaFile);
for (int i = 0; i < num_regions; i++) {
used[i] = usedRegionSizeAligned(jsaFile, i);
start = start0;
@ -163,7 +188,7 @@ public class CDSArchiveUtils {
int bufSize;
System.out.printf("%-24s%12s%12s%16s\n", "Space Name", "Used bytes", "Reg Start", "Random Offset");
start0 = fileHeaderSize;
start0 = fileHeaderSize(jsaFile);
for (int i = 0; i < num_regions; i++) {
used[i] = usedRegionSizeAligned(jsaFile, i);
start = start0;
@ -200,12 +225,12 @@ public class CDSArchiveUtils {
}
byte[] buf = new byte[4096];
System.out.printf("%-24s%12d\n", "Total: ", total);
long regionStartOffset = fileHeaderSize;
long regionStartOffset = fileHeaderSize(jsaFile);
for (int i = 0; i < region; i++) {
regionStartOffset += used[i];
}
System.out.println("Corrupt " + shared_region_name[region] + " section, start = " + regionStartOffset
+ " (header_size + 0x" + Long.toHexString(regionStartOffset - fileHeaderSize) + ")");
+ " (header_size + 0x" + Long.toHexString(regionStartOffset - fileHeaderSize(jsaFile)) + ")");
long bytesWritten = 0L;
while (bytesWritten < used[region]) {
bytesWritten += writeData(jsaFile, regionStartOffset + bytesWritten, buf);
@ -233,7 +258,7 @@ public class CDSArchiveUtils {
public static void modifyFileHeader(File jsaFile) throws Exception {
// screw up header info
byte[] buf = new byte[fileHeaderSize];
byte[] buf = new byte[(int)fileHeaderSize(jsaFile)];
writeData(jsaFile, 0, buf);
}
@ -257,6 +282,7 @@ public class CDSArchiveUtils {
throw new IOException("Could not delete file " + newJsaFile);
}
}
Files.copy(orgJsaFile.toPath(), newJsaFile.toPath(), REPLACE_EXISTING);
// change permission
@ -265,15 +291,17 @@ public class CDSArchiveUtils {
return newJsaFile;
}
private static FileChannel getFileChannel(File file) throws Exception {
private static FileChannel getFileChannel(File file, boolean write) throws Exception {
List<StandardOpenOption> arry = new ArrayList<StandardOpenOption>();
arry.add(READ);
arry.add(WRITE);
if (write) {
arry.add(WRITE);
}
return FileChannel.open(file.toPath(), new HashSet<StandardOpenOption>(arry));
}
public static long readInt(File file, long offset, int nBytes) throws Exception {
try (FileChannel fc = getFileChannel(file)) {
try (FileChannel fc = getFileChannel(file, false /*read only*/)) {
ByteBuffer bb = ByteBuffer.allocate(nBytes);
bb.order(ByteOrder.nativeOrder());
fc.position(offset);
@ -288,14 +316,14 @@ public class CDSArchiveUtils {
}
public static long writeData(File file, long offset, byte[] array) throws Exception {
try (FileChannel fc = getFileChannel(file)) {
try (FileChannel fc = getFileChannel(file, true /*write*/)) {
ByteBuffer bbuf = ByteBuffer.wrap(array);
return writeData(fc, offset, bbuf);
}
}
public static long writeData(File file, long offset, int value) throws Exception {
try (FileChannel fc = getFileChannel(file)) {
try (FileChannel fc = getFileChannel(file, true /*write*/)) {
ByteBuffer bbuf = ByteBuffer.allocate(4).putInt(value).position(0);
return writeData(fc, offset, bbuf);
}
@ -303,7 +331,7 @@ public class CDSArchiveUtils {
// dstFile will keep original size so will remove corresponding bytes.length bytes at end of file
public static File insertBytesRandomlyAfterHeader(File orgFile, String newFileName, byte[] bytes) throws Exception {
long offset = fileHeaderSize + getRandomBetween(0L, 4096L);
long offset = fileHeaderSize(orgFile) + getRandomBetween(0L, 4096L);
File dstFile = new File(newFileName);
try (FileChannel inputChannel = new FileInputStream(orgFile).getChannel();
FileChannel outputChannel = new FileOutputStream(dstFile).getChannel()) {
@ -318,7 +346,7 @@ public class CDSArchiveUtils {
// delete nBytes bytes from offset, so new file will be smaller than the original
public static File deleteBytesAtRandomPositionAfterHeader(File orgFile, String newFileName, int nBytes) throws Exception {
long offset = fileHeaderSize + getRandomBetween(0L, 4096L);
long offset = fileHeaderSize(orgFile) + getRandomBetween(0L, 4096L);
File dstFile = new File(newFileName);
try (FileChannel inputChannel = new FileInputStream(orgFile).getChannel();
FileChannel outputChannel = new FileOutputStream(dstFile).getChannel()) {

@ -559,14 +559,22 @@ public class WhiteBox {
public native void AddModuleExportsToAllUnnamed(Object module, String pkg);
public native void AddModuleExportsToAll(Object module, String pkg);
public native int getOffsetForName0(String name);
public int getOffsetForName(String name) throws Exception {
int offset = getOffsetForName0(name);
public native int getCDSOffsetForName0(String name);
public int getCDSOffsetForName(String name) throws Exception {
int offset = getCDSOffsetForName0(name);
if (offset == -1) {
throw new RuntimeException(name + " not found");
}
return offset;
}
public native int getCDSConstantForName0(String name);
public int getCDSConstantForName(String name) throws Exception {
int constant = getCDSConstantForName0(name);
if (constant == -1) {
throw new RuntimeException(name + " not found");
}
return constant;
}
public native Boolean getMethodBooleanOption(Executable method, String name);
public native Long getMethodIntxOption(Executable method, String name);
public native Long getMethodUintxOption(Executable method, String name);

@ -560,14 +560,22 @@ public class WhiteBox {
public native void AddModuleExportsToAllUnnamed(Object module, String pkg);
public native void AddModuleExportsToAll(Object module, String pkg);
public native int getOffsetForName0(String name);
public int getOffsetForName(String name) throws Exception {
int offset = getOffsetForName0(name);
public native int getCDSOffsetForName0(String name);
public int getCDSOffsetForName(String name) throws Exception {
int offset = getCDSOffsetForName0(name);
if (offset == -1) {
throw new RuntimeException(name + " not found");
}
return offset;
}
public native int getCDSConstantForName0(String name);
public int getCDSConstantForName(String name) throws Exception {
int constant = getCDSConstantForName0(name);
if (constant == -1) {
throw new RuntimeException(name + " not found");
}
return constant;
}
public native Boolean getMethodBooleanOption(Executable method, String name);
public native Long getMethodIntxOption(Executable method, String name);
public native Long getMethodUintxOption(Executable method, String name);