This commit is contained in:
Jean-Francois Denise 2015-06-25 20:47:46 +00:00
commit 88ff99b454
40 changed files with 2815 additions and 322 deletions

View File

@ -141,6 +141,18 @@ SUNWprivate_1.1 {
JVM_Halt;
JVM_HoldsLock;
JVM_IHashCode;
JVM_ImageAttributeOffsets;
JVM_ImageAttributeOffsetsLength;
JVM_ImageClose;
JVM_ImageFindAttributes;
JVM_ImageGetAttributes;
JVM_ImageGetAttributesCount;
JVM_ImageGetDataAddress;
JVM_ImageGetIndexAddress;
JVM_ImageGetStringBytes;
JVM_ImageOpen;
JVM_ImageRead;
JVM_ImageReadCompressed;
JVM_InitAgentProperties;
JVM_InitProperties;
JVM_InternString;

View File

@ -139,6 +139,18 @@ SUNWprivate_1.1 {
JVM_Halt;
JVM_HoldsLock;
JVM_IHashCode;
JVM_ImageAttributeOffsets;
JVM_ImageAttributeOffsetsLength;
JVM_ImageClose;
JVM_ImageFindAttributes;
JVM_ImageGetAttributes;
JVM_ImageGetAttributesCount;
JVM_ImageGetDataAddress;
JVM_ImageGetIndexAddress;
JVM_ImageGetStringBytes;
JVM_ImageOpen;
JVM_ImageRead;
JVM_ImageReadCompressed;
JVM_InitAgentProperties;
JVM_InitProperties;
JVM_InternString;

View File

@ -139,6 +139,18 @@
_JVM_Halt
_JVM_HoldsLock
_JVM_IHashCode
_JVM_ImageAttributeOffsets
_JVM_ImageAttributeOffsetsLength
_JVM_ImageClose
_JVM_ImageFindAttributes
_JVM_ImageGetAttributes
_JVM_ImageGetAttributesCount
_JVM_ImageGetDataAddress
_JVM_ImageGetIndexAddress
_JVM_ImageGetStringBytes
_JVM_ImageOpen
_JVM_ImageRead
_JVM_ImageReadCompressed
_JVM_InitAgentProperties
_JVM_InitProperties
_JVM_InternString
@ -188,7 +200,7 @@
_JVM_Yield
_JVM_handle_bsd_signal
# miscellaneous functions
# miscellaneous functions
_jio_fprintf
_jio_printf
_jio_snprintf

View File

@ -139,6 +139,18 @@
_JVM_Halt
_JVM_HoldsLock
_JVM_IHashCode
_JVM_ImageAttributeOffsets
_JVM_ImageAttributeOffsetsLength
_JVM_ImageClose
_JVM_ImageFindAttributes
_JVM_ImageGetAttributes
_JVM_ImageGetAttributesCount
_JVM_ImageGetDataAddress
_JVM_ImageGetIndexAddress
_JVM_ImageGetStringBytes
_JVM_ImageOpen
_JVM_ImageRead
_JVM_ImageReadCompressed
_JVM_InitAgentProperties
_JVM_InitProperties
_JVM_InternString

View File

@ -141,6 +141,18 @@ SUNWprivate_1.1 {
JVM_Halt;
JVM_HoldsLock;
JVM_IHashCode;
JVM_ImageAttributeOffsets;
JVM_ImageAttributeOffsetsLength;
JVM_ImageClose;
JVM_ImageFindAttributes;
JVM_ImageGetAttributes;
JVM_ImageGetAttributesCount;
JVM_ImageGetDataAddress;
JVM_ImageGetIndexAddress;
JVM_ImageGetStringBytes;
JVM_ImageOpen;
JVM_ImageRead;
JVM_ImageReadCompressed;
JVM_InitAgentProperties;
JVM_InitProperties;
JVM_InternString;

View File

@ -141,6 +141,18 @@ SUNWprivate_1.1 {
JVM_Halt;
JVM_HoldsLock;
JVM_IHashCode;
JVM_ImageAttributeOffsets;
JVM_ImageAttributeOffsetsLength;
JVM_ImageClose;
JVM_ImageFindAttributes;
JVM_ImageGetAttributes;
JVM_ImageGetAttributesCount;
JVM_ImageGetDataAddress;
JVM_ImageGetIndexAddress;
JVM_ImageGetStringBytes;
JVM_ImageOpen;
JVM_ImageRead;
JVM_ImageReadCompressed;
JVM_InitAgentProperties;
JVM_InitProperties;
JVM_InternString;

View File

@ -141,6 +141,18 @@ SUNWprivate_1.1 {
JVM_Halt;
JVM_HoldsLock;
JVM_IHashCode;
JVM_ImageAttributeOffsets;
JVM_ImageAttributeOffsetsLength;
JVM_ImageClose;
JVM_ImageFindAttributes;
JVM_ImageGetAttributes;
JVM_ImageGetAttributesCount;
JVM_ImageGetDataAddress;
JVM_ImageGetIndexAddress;
JVM_ImageGetStringBytes;
JVM_ImageOpen;
JVM_ImageRead;
JVM_ImageReadCompressed;
JVM_InitAgentProperties;
JVM_InitProperties;
JVM_InternString;

View File

@ -141,6 +141,18 @@ SUNWprivate_1.1 {
JVM_Halt;
JVM_HoldsLock;
JVM_IHashCode;
JVM_ImageAttributeOffsets;
JVM_ImageAttributeOffsetsLength;
JVM_ImageClose;
JVM_ImageFindAttributes;
JVM_ImageGetAttributes;
JVM_ImageGetAttributesCount;
JVM_ImageGetDataAddress;
JVM_ImageGetIndexAddress;
JVM_ImageGetStringBytes;
JVM_ImageOpen;
JVM_ImageRead;
JVM_ImageReadCompressed;
JVM_InitAgentProperties;
JVM_InitProperties;
JVM_InternString;

View File

@ -141,6 +141,18 @@ SUNWprivate_1.1 {
JVM_Halt;
JVM_HoldsLock;
JVM_IHashCode;
JVM_ImageAttributeOffsets;
JVM_ImageAttributeOffsetsLength;
JVM_ImageClose;
JVM_ImageFindAttributes;
JVM_ImageGetAttributes;
JVM_ImageGetAttributesCount;
JVM_ImageGetDataAddress;
JVM_ImageGetIndexAddress;
JVM_ImageGetStringBytes;
JVM_ImageOpen;
JVM_ImageRead;
JVM_ImageReadCompressed;
JVM_InitAgentProperties;
JVM_InitProperties;
JVM_InternString;

View File

@ -68,7 +68,6 @@
#include "classfile/sharedPathsMiscInfo.hpp"
#endif
// Entry points in zip.dll for loading zip/jar file entries and image file entries
typedef void * * (JNICALL *ZipOpen_t)(const char *name, char **pmsg);
@ -167,7 +166,6 @@ ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() {
_dir = copy;
}
ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
// construct full path name
char path[JVM_MAXPATHLEN];
@ -352,16 +350,25 @@ u1* LazyClassPathEntry::open_entry(const char* name, jint* filesize, bool nul_te
}
}
ClassPathImageEntry::ClassPathImageEntry(char* name) : ClassPathEntry(), _image(new ImageFile(name)) {
bool opened = _image->open();
if (!opened) {
_image = NULL;
}
ClassPathImageEntry::ClassPathImageEntry(ImageFileReader* image) :
ClassPathEntry(),
_image(image),
_module_data(NULL) {
guarantee(image != NULL, "image file is null");
char module_data_name[JVM_MAXPATHLEN];
ImageModuleData::module_data_name(module_data_name, _image->name());
_module_data = new ImageModuleData(_image, module_data_name);
}
ClassPathImageEntry::~ClassPathImageEntry() {
if (_image) {
_image->close();
if (_module_data != NULL) {
delete _module_data;
_module_data = NULL;
}
if (_image != NULL) {
ImageFileReader::close(_image);
_image = NULL;
}
}
@ -371,15 +378,39 @@ const char* ClassPathImageEntry::name() {
}
ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
u1* buffer;
u8 size;
_image->get_resource(name, buffer, size);
ImageLocation location;
bool found = _image->find_location(name, location);
if (buffer) {
if (!found) {
const char *pslash = strrchr(name, '/');
int len = pslash - name;
// NOTE: IMAGE_MAX_PATH is used here since this path is internal to the jimage
// (effectively unlimited.) There are several JCK tests that use paths over
// 1024 characters long, the limit on Windows systems.
if (pslash && 0 < len && len < IMAGE_MAX_PATH) {
char path[IMAGE_MAX_PATH];
strncpy(path, name, len);
path[len] = '\0';
const char* moduleName = _module_data->package_to_module(path);
if (moduleName != NULL && (len + strlen(moduleName) + 2) < IMAGE_MAX_PATH) {
jio_snprintf(path, IMAGE_MAX_PATH - 1, "/%s/%s", moduleName, name);
location.clear_data();
found = _image->find_location(path, location);
}
}
}
if (found) {
u8 size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
if (UsePerfData) {
ClassLoader::perf_sys_classfile_bytes_read()->inc(size);
}
return new ClassFileStream(buffer, (int)size, (char*)name); // Resource allocated
u1* data = NEW_RESOURCE_ARRAY(u1, size);
_image->get_resource(location, data);
return new ClassFileStream(data, (int)size, _image->name()); // Resource allocated
}
return NULL;
@ -391,20 +422,14 @@ void ClassPathImageEntry::compile_the_world(Handle loader, TRAPS) {
tty->cr();
const ImageStrings strings = _image->get_strings();
// Retrieve each path component string.
u4 count = _image->get_location_count();
for (u4 i = 0; i < count; i++) {
u4 length = _image->table_length();
for (u4 i = 0; i < length; i++) {
u1* location_data = _image->get_location_data(i);
if (location_data) {
if (location_data != NULL) {
ImageLocation location(location_data);
const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);
const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings);
const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);
assert((strlen(parent) + strlen(base) + strlen(extension)) < JVM_MAXPATHLEN, "path exceeds buffer");
char path[JVM_MAXPATHLEN];
strcpy(path, parent);
strcat(path, base);
strcat(path, extension);
char path[IMAGE_MAX_PATH];
_image->location_path(location, path, IMAGE_MAX_PATH);
ClassLoader::compile_the_world_in(path, loader, CHECK);
}
}
@ -420,7 +445,7 @@ void ClassPathImageEntry::compile_the_world(Handle loader, TRAPS) {
}
bool ClassPathImageEntry::is_jrt() {
return string_ends_with(name(), "bootmodules.jimage");
return string_ends_with(name(), BOOT_IMAGE_NAME);
}
#endif
@ -557,10 +582,9 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str
return NULL;
}
}
// TODO - add proper criteria for selecting image file
ClassPathImageEntry* entry = new ClassPathImageEntry(canonical_path);
if (entry->is_open()) {
new_entry = entry;
ImageFileReader* image = ImageFileReader::open(canonical_path);
if (image != NULL) {
new_entry = new ClassPathImageEntry(image);
} else {
char* error_msg = NULL;
jzfile* zip;

View File

@ -32,9 +32,14 @@
// The VM class loader.
#include <sys/stat.h>
// Name of boot module image
#define BOOT_IMAGE_NAME "bootmodules.jimage"
// Class path entry (directory or zip file)
class ImageFileReader;
class ImageModuleData;
class ClassPathEntry: public CHeapObj<mtClass> {
private:
ClassPathEntry* _next;
@ -47,6 +52,7 @@ class ClassPathEntry: public CHeapObj<mtClass> {
}
virtual bool is_jar_file() = 0;
virtual const char* name() = 0;
virtual ImageFileReader* image() = 0;
virtual bool is_lazy();
// Constructor
ClassPathEntry();
@ -63,8 +69,9 @@ class ClassPathDirEntry: public ClassPathEntry {
private:
const char* _dir; // Name of directory
public:
bool is_jar_file() { return false; }
const char* name() { return _dir; }
bool is_jar_file() { return false; }
const char* name() { return _dir; }
ImageFileReader* image() { return NULL; }
ClassPathDirEntry(const char* dir);
ClassFileStream* open_stream(const char* name, TRAPS);
// Debugging
@ -92,8 +99,9 @@ class ClassPathZipEntry: public ClassPathEntry {
jzfile* _zip; // The zip archive
const char* _zip_name; // Name of zip archive
public:
bool is_jar_file() { return true; }
const char* name() { return _zip_name; }
bool is_jar_file() { return true; }
const char* name() { return _zip_name; }
ImageFileReader* image() { return NULL; }
ClassPathZipEntry(jzfile* zip, const char* zip_name);
~ClassPathZipEntry();
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
@ -116,7 +124,8 @@ class LazyClassPathEntry: public ClassPathEntry {
ClassPathEntry* resolve_entry(TRAPS);
public:
bool is_jar_file();
const char* name() { return _path; }
const char* name() { return _path; }
ImageFileReader* image() { return NULL; }
LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception);
virtual ~LazyClassPathEntry();
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
@ -129,15 +138,17 @@ class LazyClassPathEntry: public ClassPathEntry {
};
// For java image files
class ImageFile;
class ClassPathImageEntry: public ClassPathEntry {
private:
ImageFile *_image;
ImageFileReader* _image;
ImageModuleData* _module_data;
public:
bool is_jar_file() { return false; }
bool is_open() { return _image != NULL; }
const char* name();
ClassPathImageEntry(char* name);
ImageFileReader* image() { return _image; }
ImageModuleData* module_data() { return _module_data; }
ClassPathImageEntry(ImageFileReader* image);
~ClassPathImageEntry();
ClassFileStream* open_stream(const char* name, TRAPS);

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2015, 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 "runtime/thread.inline.hpp"
#include "precompiled.hpp"
#include "classfile/imageDecompressor.hpp"
#include "runtime/thread.hpp"
#include "utilities/bytes.hpp"
/*
* Allocate in C Heap not in resource area, otherwise JVM crashes.
* This array life time is the VM life time. Array is never freed and
* is not expected to contain more than few references.
*/
GrowableArray<ImageDecompressor*>* ImageDecompressor::_decompressors =
new(ResourceObj::C_HEAP, mtInternal) GrowableArray<ImageDecompressor*>(2, true);
static Symbol* createSymbol(const char* str) {
Thread* THREAD = Thread::current();
Symbol* sym = SymbolTable::lookup(str, (int) strlen(str), THREAD);
if (HAS_PENDING_EXCEPTION) {
warning("can't create symbol\n");
CLEAR_PENDING_EXCEPTION;
return NULL;
}
return sym;
}
/*
* Initialize the array of decompressors.
*/
bool image_decompressor_init() {
Symbol* zipSymbol = createSymbol("zip");
if (zipSymbol == NULL) {
return false;
}
ImageDecompressor::add_decompressor(new ZipDecompressor(zipSymbol));
return true;
}
/*
* Decompression entry point. Called from ImageFileReader::get_resource.
*/
void ImageDecompressor::decompress_resource(u1* compressed, u1* uncompressed,
u4 uncompressed_size, const ImageStrings* strings, bool is_C_heap) {
bool has_header = false;
u1* decompressed_resource = compressed;
u1* compressed_resource = compressed;
// Resource could have been transformed by a stack of decompressors.
// Iterate and decompress resources until there is no more header.
do {
ResourceHeader _header;
memcpy(&_header, compressed_resource, sizeof (ResourceHeader));
has_header = _header._magic == ResourceHeader::resource_header_magic;
if (has_header) {
// decompressed_resource array contains the result of decompression
// when a resource content is terminal, it means that it is an actual resource,
// not an intermediate not fully uncompressed content. In this case
// the resource is allocated as an mtClass, otherwise as an mtOther
decompressed_resource = is_C_heap && _header._is_terminal ?
NEW_C_HEAP_ARRAY(u1, _header._uncompressed_size, mtClass) :
NEW_C_HEAP_ARRAY(u1, _header._uncompressed_size, mtOther);
// Retrieve the decompressor name
const char* decompressor_name = strings->get(_header._decompressor_name_offset);
if (decompressor_name == NULL) warning("image decompressor not found\n");
guarantee(decompressor_name, "image decompressor not found");
// Retrieve the decompressor instance
ImageDecompressor* decompressor = get_decompressor(decompressor_name);
if (decompressor == NULL) {
warning("image decompressor %s not found\n", decompressor_name);
}
guarantee(decompressor, "image decompressor not found");
u1* compressed_resource_base = compressed_resource;
compressed_resource += ResourceHeader::resource_header_length;
// Ask the decompressor to decompress the compressed content
decompressor->decompress_resource(compressed_resource, decompressed_resource,
&_header, strings);
if (compressed_resource_base != compressed) {
FREE_C_HEAP_ARRAY(char, compressed_resource_base);
}
compressed_resource = decompressed_resource;
}
} while (has_header);
memcpy(uncompressed, decompressed_resource, uncompressed_size);
}
// Zip decompressor
void ZipDecompressor::decompress_resource(u1* data, u1* uncompressed,
ResourceHeader* header, const ImageStrings* strings) {
char* msg = NULL;
jboolean res = ClassLoader::decompress(data, header->_size, uncompressed,
header->_uncompressed_size, &msg);
if (!res) warning("decompression failed due to %s\n", msg);
guarantee(res, "decompression failed");
}
// END Zip Decompressor

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2015, 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.
*
*/
#ifndef SHARE_VM_CLASSFILE_IMAGEDECOMPRESSOR_HPP
#define SHARE_VM_CLASSFILE_IMAGEDECOMPRESSOR_HPP
#include "runtime/thread.inline.hpp"
#include "precompiled.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/imageFile.hpp"
#include "classfile/symbolTable.hpp"
#include "oops/symbol.hpp"
#include "utilities/growableArray.hpp"
/*
* Compressed resources located in image have an header.
* This header contains:
* - _magic: A magic u4, required to retrieved the header in the compressed content
* - _size: The size of the compressed resource.
* - _uncompressed_size: The uncompressed size of the compressed resource.
* - _decompressor_name_offset: The ImageDecompressor instance name StringsTable offset.
* - _decompressor_config_offset: StringsTable offset of configuration that could be needed by
* the decompressor in order to decompress.
* - _is_terminal: 1: the compressed content is terminal. Uncompressing it would
* create the actual resource. 0: the compressed content is not terminal. Uncompressing it
* will result in a compressed content to be decompressed (This occurs when a stack of compressors
* have been used to compress the resource.
*/
struct ResourceHeader {
/* Length of header, needed to retrieve content offset */
static const u1 resource_header_length = 21;
/* magic bytes that identifies a compressed resource header*/
static const u4 resource_header_magic = 0xCAFEFAFA;
u4 _magic; // Resource header
u4 _size; // Resource size
u4 _uncompressed_size; // Expected uncompressed size
u4 _decompressor_name_offset; // Strings table decompressor offset
u4 _decompressor_config_offset; // Strings table config offset
u1 _is_terminal; // Last decompressor 1, otherwise 0.
};
/*
* Resources located in jimage file can be compressed. Compression occurs at
* jimage file creation time. When compressed a resource is added an header that
* contains the name of the compressor that compressed it.
* Various compression strategies can be applied to compress a resource.
* The same resource can even be compressed multiple time by a stack of compressors.
* At runtime, a resource is decompressed in a loop until there is no more header
* meaning that the resource is equivalent to the not compressed resource.
* In each iteration, the name of the compressor located in the current header
* is used to retrieve the associated instance of ImageDecompressor.
* For example zip is the name of the compressor that compresses resources
* using the zip algorithm. The ZipDecompressor class name is also zip.
* ImageDecompressor instances are retrieved from a static array in which
* they are registered.
*/
class ImageDecompressor: public CHeapObj<mtClass> {
private:
const Symbol* _name;
/*
* Array of concrete decompressors. This array is used to retrieve the decompressor
* that can handle resource decompression.
*/
static GrowableArray<ImageDecompressor*>* _decompressors;
/*
* Identifier of a decompressor. This name is the identification key to retrieve
* decompressor from a resource header.
*/
inline const Symbol* get_name() const { return _name; }
protected:
ImageDecompressor(const Symbol* name) : _name(name) {
}
virtual void decompress_resource(u1* data, u1* uncompressed,
ResourceHeader* header, const ImageStrings* strings) = 0;
public:
inline static void add_decompressor(ImageDecompressor* decompressor) {
_decompressors->append(decompressor);
}
inline static ImageDecompressor* get_decompressor(const char * decompressor_name) {
Thread* THREAD = Thread::current();
TempNewSymbol sym = SymbolTable::new_symbol(decompressor_name,
(int) strlen(decompressor_name), CHECK_NULL);
if (HAS_PENDING_EXCEPTION) {
warning("can't create symbol\n");
CLEAR_PENDING_EXCEPTION;
return NULL;
}
for (int i = 0; i < _decompressors->length(); i++) {
ImageDecompressor* decompressor = _decompressors->at(i);
if (decompressor->get_name()->fast_compare(sym) == 0) {
return decompressor;
}
}
guarantee(false, "No decompressor found.");
return NULL;
}
static void decompress_resource(u1* compressed, u1* uncompressed,
u4 uncompressed_size, const ImageStrings* strings, bool is_C_heap);
};
/**
* Zip decompressor.
*/
class ZipDecompressor : public ImageDecompressor {
public:
ZipDecompressor(const Symbol* sym) : ImageDecompressor(sym) { }
void decompress_resource(u1* data, u1* uncompressed, ResourceHeader* header,
const ImageStrings* strings);
};
#endif // SHARE_VM_CLASSFILE_IMAGEDECOMPRESSOR_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -23,77 +23,311 @@
*/
#include "precompiled.hpp"
#include "classfile/imageDecompressor.hpp"
#include "classfile/imageFile.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/os.inline.hpp"
#include "utilities/bytes.hpp"
#include "utilities/endian.hpp"
#include "utilities/growableArray.hpp"
// Image files are an alternate file format for storing classes and resources. The
// goal is to supply file access which is faster and smaller than the jar format.
//
// (More detailed nodes in the header.)
//
// Compute the Perfect Hashing hash code for the supplied string.
u4 ImageStrings::hash_code(const char* string, u4 seed) {
// Compute the Perfect Hashing hash code for the supplied UTF-8 string.
s4 ImageStrings::hash_code(const char* string, s4 seed) {
// Access bytes as unsigned.
u1* bytes = (u1*)string;
// Compute hash code.
for (u1 byte = *bytes++; byte; byte = *bytes++) {
seed = (seed * HASH_MULTIPLIER) ^ byte;
}
// Ensure the result is unsigned.
// Ensure the result is not signed.
return seed & 0x7FFFFFFF;
}
// Test to see if string begins with start. If so returns remaining portion
// of string. Otherwise, NULL.
// Match up a string in a perfect hash table. Result still needs validation
// for precise match (false positive.)
s4 ImageStrings::find(Endian* endian, const char* name, s4* redirect, u4 length) {
// If the table is empty, then short cut.
if (redirect == NULL || length == 0) {
return NOT_FOUND;
}
// Compute the basic perfect hash for name.
s4 hash_code = ImageStrings::hash_code(name);
// Modulo table size.
s4 index = hash_code % length;
// Get redirect entry.
// value == 0 then not found
// value < 0 then -1 - value is true index
// value > 0 then value is seed for recomputing hash.
s4 value = endian->get(redirect[index]);
// if recompute is required.
if (value > 0) {
// Entry collision value, need to recompute hash.
hash_code = ImageStrings::hash_code(name, value);
// Modulo table size.
return hash_code % length;
} else if (value < 0) {
// Compute direct index.
return -1 - value;
}
// No entry found.
return NOT_FOUND;
}
// Test to see if UTF-8 string begins with the start UTF-8 string. If so,
// return non-NULL address of remaining portion of string. Otherwise, return
// NULL. Used to test sections of a path without copying from image string
// table.
const char* ImageStrings::starts_with(const char* string, const char* start) {
char ch1, ch2;
// Match up the strings the best we can.
while ((ch1 = *string) && (ch2 = *start)) {
if (ch1 != ch2) {
// Mismatch, return NULL.
return NULL;
}
// Next characters.
string++, start++;
}
// Return remainder of string.
return string;
}
ImageLocation::ImageLocation(u1* data) {
// Inflates the attribute stream into individual values stored in the long
// array _attributes. This allows an attribute value to be quickly accessed by
// direct indexing. Unspecified values default to zero (from constructor.)
void ImageLocation::set_data(u1* data) {
// Deflate the attribute stream into an array of attributes.
memset(_attributes, 0, sizeof(_attributes));
u1 byte;
while ((byte = *data) != ATTRIBUTE_END) {
// Repeat until end header is found.
while ((byte = *data)) {
// Extract kind from header byte.
u1 kind = attribute_kind(byte);
guarantee(kind < ATTRIBUTE_COUNT, "invalid image location attribute");
// Extract length of data (in bytes).
u1 n = attribute_length(byte);
assert(kind < ATTRIBUTE_COUNT, "invalid image location attribute");
// Read value (most significant first.)
_attributes[kind] = attribute_value(data + 1, n);
// Position to next attribute by skipping attribute header and data bytes.
data += n + 1;
}
}
ImageFile::ImageFile(const char* name) {
// Copy the image file name.
_name = NEW_C_HEAP_ARRAY(char, strlen(name)+1, mtClass);
strcpy(_name, name);
// Zero all attribute values.
void ImageLocation::clear_data() {
// Set defaults to zero.
memset(_attributes, 0, sizeof(_attributes));
}
// ImageModuleData constructor maps out sub-tables for faster access.
ImageModuleData::ImageModuleData(const ImageFileReader* image_file,
const char* module_data_name) :
_image_file(image_file),
_endian(image_file->endian()),
_strings(image_file->get_strings()) {
// Retrieve the resource containing the module data for the image file.
ImageLocation location;
bool found = image_file->find_location(module_data_name, location);
guarantee(found, "missing module data");
u8 data_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
_data = (u1*)NEW_C_HEAP_ARRAY(char, data_size, mtClass);
_image_file->get_resource(location, _data);
// Map out the header.
_header = (Header*)_data;
// Get the package to module entry count.
u4 ptm_count = _header->ptm_count(_endian);
// Get the module to package entry count.
u4 mtp_count = _header->mtp_count(_endian);
// Compute the offset of the package to module perfect hash redirect.
u4 ptm_redirect_offset = sizeof(Header);
// Compute the offset of the package to module data.
u4 ptm_data_offset = ptm_redirect_offset + ptm_count * sizeof(s4);
// Compute the offset of the module to package perfect hash redirect.
u4 mtp_redirect_offset = ptm_data_offset + ptm_count * sizeof(PTMData);
// Compute the offset of the module to package data.
u4 mtp_data_offset = mtp_redirect_offset + mtp_count * sizeof(s4);
// Compute the offset of the module to package tables.
u4 mtp_packages_offset = mtp_data_offset + mtp_count * sizeof(MTPData);
// Compute the address of the package to module perfect hash redirect.
_ptm_redirect = (s4*)(_data + ptm_redirect_offset);
// Compute the address of the package to module data.
_ptm_data = (PTMData*)(_data + ptm_data_offset);
// Compute the address of the module to package perfect hash redirect.
_mtp_redirect = (s4*)(_data + mtp_redirect_offset);
// Compute the address of the module to package data.
_mtp_data = (MTPData*)(_data + mtp_data_offset);
// Compute the address of the module to package tables.
_mtp_packages = (s4*)(_data + mtp_packages_offset);
}
// Release module data resource.
ImageModuleData::~ImageModuleData() {
if (_data != NULL) {
FREE_C_HEAP_ARRAY(u1, _data);
}
}
// Return the name of the module data resource. Ex. "./lib/modules/file.jimage"
// yields "file.jdata"
void ImageModuleData::module_data_name(char* buffer, const char* image_file_name) {
// Locate the last slash in the file name path.
const char* slash = strrchr(image_file_name, os::file_separator()[0]);
// Trim the path to name and extension.
const char* name = slash != NULL ? slash + 1 : (char *)image_file_name;
// Locate the extension period.
const char* dot = strrchr(name, '.');
guarantee(dot, "missing extension on jimage name");
// Trim to only base name.
int length = dot - name;
strncpy(buffer, name, length);
buffer[length] = '\0';
// Append extension.
strcat(buffer, ".jdata");
}
// Return the module in which a package resides. Returns NULL if not found.
const char* ImageModuleData::package_to_module(const char* package_name) {
// Search the package to module table.
s4 index = ImageStrings::find(_endian, package_name, _ptm_redirect,
_header->ptm_count(_endian));
// If entry is found.
if (index != ImageStrings::NOT_FOUND) {
// Retrieve the package to module entry.
PTMData* data = _ptm_data + index;
// Verify that it is the correct data.
if (strcmp(package_name, get_string(data->name_offset(_endian))) != 0) {
return NULL;
}
// Return the module name.
return get_string(data->module_name_offset(_endian));
}
return NULL;
}
// Returns all the package names in a module. Returns NULL if module not found.
GrowableArray<const char*>* ImageModuleData::module_to_packages(const char* module_name) {
// Search the module to package table.
s4 index = ImageStrings::find(_endian, module_name, _mtp_redirect,
_header->mtp_count(_endian));
// If entry is found.
if (index != ImageStrings::NOT_FOUND) {
// Retrieve the module to package entry.
MTPData* data = _mtp_data + index;
// Verify that it is the correct data.
if (strcmp(module_name, get_string(data->name_offset(_endian))) != 0) {
return NULL;
}
// Construct an array of all the package entries.
GrowableArray<const char*>* packages = new GrowableArray<const char*>();
s4 package_offset = data->package_offset(_endian);
for (u4 i = 0; i < data->package_count(_endian); i++) {
u4 package_name_offset = mtp_package(package_offset + i);
const char* package_name = get_string(package_name_offset);
packages->append(package_name);
}
return packages;
}
return NULL;
}
// Table to manage multiple opens of an image file.
GrowableArray<ImageFileReader*>* ImageFileReader::_reader_table =
new(ResourceObj::C_HEAP, mtInternal) GrowableArray<ImageFileReader*>(2, true);
// Open an image file, reuse structure if file already open.
ImageFileReader* ImageFileReader::open(const char* name, bool big_endian) {
// Lock out _reader_table.
MutexLocker ml(ImageFileReaderTable_lock);
ImageFileReader* reader;
// Search for an exist image file.
for (int i = 0; i < _reader_table->length(); i++) {
// Retrieve table entry.
reader = _reader_table->at(i);
// If name matches, then reuse (bump up use count.)
if (strcmp(reader->name(), name) == 0) {
reader->inc_use();
return reader;
}
}
// Need a new image reader.
reader = new ImageFileReader(name, big_endian);
bool opened = reader->open();
// If failed to open.
if (!opened) {
delete reader;
return NULL;
}
// Bump use count and add to table.
reader->inc_use();
_reader_table->append(reader);
return reader;
}
// Close an image file if the file is not in use elsewhere.
void ImageFileReader::close(ImageFileReader *reader) {
// Lock out _reader_table.
MutexLocker ml(ImageFileReaderTable_lock);
// If last use then remove from table and then close.
if (reader->dec_use()) {
_reader_table->remove(reader);
delete reader;
}
}
// Return an id for the specifed ImageFileReader.
u8 ImageFileReader::readerToID(ImageFileReader *reader) {
// ID is just the cloaked reader address.
return (u8)reader;
}
// Validate the image id.
bool ImageFileReader::idCheck(u8 id) {
// Make sure the ID is a managed (_reader_table) reader.
MutexLocker ml(ImageFileReaderTable_lock);
return _reader_table->contains((ImageFileReader*)id);
}
// Return an id for the specifed ImageFileReader.
ImageFileReader* ImageFileReader::idToReader(u8 id) {
#ifdef PRODUCT
// Fast convert.
return (ImageFileReader*)id;
#else
// Do a slow check before fast convert.
return idCheck(id) ? (ImageFileReader*)id : NULL;
#endif
}
// Constructor intializes to a closed state.
ImageFileReader::ImageFileReader(const char* name, bool big_endian) {
// Copy the image file name.
_name = NEW_C_HEAP_ARRAY(char, strlen(name) + 1, mtClass);
strcpy(_name, name);
// Initialize for a closed file.
_fd = -1;
_memory_mapped = true;
_endian = Endian::get_handler(big_endian);
_index_data = NULL;
}
ImageFile::~ImageFile() {
// Close image and free up data structures.
ImageFileReader::~ImageFileReader() {
// Ensure file is closed.
close();
// Free up name.
FREE_C_HEAP_ARRAY(char, _name);
if (_name != NULL) {
FREE_C_HEAP_ARRAY(char, _name);
_name = NULL;
}
}
bool ImageFile::open() {
// Open image file for read access.
bool ImageFileReader::open() {
// If file exists open for reading.
struct stat st;
if (os::stat(_name, &st) != 0 ||
@ -101,186 +335,212 @@ bool ImageFile::open() {
(_fd = os::open(_name, 0, O_RDONLY)) == -1) {
return false;
}
// Read image file header and verify.
u8 header_size = sizeof(ImageHeader);
if (os::read(_fd, &_header, header_size) != header_size ||
_header._magic != IMAGE_MAGIC ||
_header._major_version != MAJOR_VERSION ||
_header._minor_version != MINOR_VERSION) {
// Retrieve the file size.
_file_size = (u8)st.st_size;
// Read image file header and verify it has a valid header.
size_t header_size = sizeof(ImageHeader);
if (_file_size < header_size ||
!read_at((u1*)&_header, header_size, 0) ||
_header.magic(_endian) != IMAGE_MAGIC ||
_header.major_version(_endian) != MAJOR_VERSION ||
_header.minor_version(_endian) != MINOR_VERSION) {
close();
return false;
}
// Memory map index.
// Size of image index.
_index_size = index_size();
_index_data = (u1*)os::map_memory(_fd, _name, 0, NULL, _index_size, true, false);
// Failing that, read index into C memory.
if (_index_data == NULL) {
_memory_mapped = false;
_index_data = NEW_RESOURCE_ARRAY(u1, _index_size);
if (os::seek_to_file_offset(_fd, 0) == -1) {
close();
return false;
}
if (os::read(_fd, _index_data, _index_size) != _index_size) {
close();
return false;
}
return true;
// Make sure file is large enough to contain the index.
if (_file_size < _index_size) {
return false;
}
// Used to advance a pointer, unstructured.
#undef nextPtr
#define nextPtr(base, fromType, count, toType) (toType*)((fromType*)(base) + (count))
// Pull tables out from the index.
_redirect_table = nextPtr(_index_data, u1, header_size, s4);
_offsets_table = nextPtr(_redirect_table, s4, _header._location_count, u4);
_location_bytes = nextPtr(_offsets_table, u4, _header._location_count, u1);
_string_bytes = nextPtr(_location_bytes, u1, _header._locations_size, u1);
#undef nextPtr
// Determine how much of the image is memory mapped.
off_t map_size = (off_t)(MemoryMapImage ? _file_size : _index_size);
// Memory map image (minimally the index.)
_index_data = (u1*)os::map_memory(_fd, _name, 0, NULL, map_size, true, false);
guarantee(_index_data, "image file not memory mapped");
// Retrieve length of index perfect hash table.
u4 length = table_length();
// Compute offset of the perfect hash table redirect table.
u4 redirect_table_offset = (u4)header_size;
// Compute offset of index attribute offsets.
u4 offsets_table_offset = redirect_table_offset + length * sizeof(s4);
// Compute offset of index location attribute data.
u4 location_bytes_offset = offsets_table_offset + length * sizeof(u4);
// Compute offset of index string table.
u4 string_bytes_offset = location_bytes_offset + locations_size();
// Compute address of the perfect hash table redirect table.
_redirect_table = (s4*)(_index_data + redirect_table_offset);
// Compute address of index attribute offsets.
_offsets_table = (u4*)(_index_data + offsets_table_offset);
// Compute address of index location attribute data.
_location_bytes = _index_data + location_bytes_offset;
// Compute address of index string table.
_string_bytes = _index_data + string_bytes_offset;
// Successful open.
return true;
}
void ImageFile::close() {
// Close image file.
void ImageFileReader::close() {
// Dealllocate the index.
if (_index_data) {
if (_memory_mapped) {
os::unmap_memory((char*)_index_data, _index_size);
} else {
FREE_RESOURCE_ARRAY(u1, _index_data, _index_size);
}
if (_index_data != NULL) {
os::unmap_memory((char*)_index_data, _index_size);
_index_data = NULL;
}
// close file.
// Close file.
if (_fd != -1) {
os::close(_fd);
_fd = -1;
}
}
// Return the attribute stream for a named resourced.
u1* ImageFile::find_location_data(const char* path) const {
// Compute hash.
u4 hash = ImageStrings::hash_code(path) % _header._location_count;
s4 redirect = _redirect_table[hash];
if (!redirect) {
return NULL;
}
u4 index;
if (redirect < 0) {
// If no collision.
index = -redirect - 1;
} else {
// If collision, recompute hash code.
index = ImageStrings::hash_code(path, redirect) % _header._location_count;
}
assert(index < _header._location_count, "index exceeds location count");
u4 offset = _offsets_table[index];
assert(offset < _header._locations_size, "offset exceeds location attributes size");
if (offset == 0) {
return NULL;
}
return _location_bytes + offset;
// Read directly from the file.
bool ImageFileReader::read_at(u1* data, u8 size, u8 offset) const {
return os::read_at(_fd, data, size, offset) == size;
}
// Verify that a found location matches the supplied path.
bool ImageFile::verify_location(ImageLocation& location, const char* path) const {
// Retrieve each path component string.
ImageStrings strings(_string_bytes, _header._strings_size);
// Match a path with each subcomponent without concatenation (copy).
// Match up path parent.
// Find the location attributes associated with the path. Returns true if
// the location is found, false otherwise.
bool ImageFileReader::find_location(const char* path, ImageLocation& location) const {
// Locate the entry in the index perfect hash table.
s4 index = ImageStrings::find(_endian, path, _redirect_table, table_length());
// If is found.
if (index != ImageStrings::NOT_FOUND) {
// Get address of first byte of location attribute stream.
u1* data = get_location_data(index);
// Expand location attributes.
location.set_data(data);
// Make sure result is not a false positive.
return verify_location(location, path);
}
return false;
}
// Assemble the location path from the string fragments indicated in the location attributes.
void ImageFileReader::location_path(ImageLocation& location, char* path, size_t max) const {
// Manage the image string table.
ImageStrings strings(_string_bytes, _header.strings_size(_endian));
// Position to first character of the path buffer.
char* next = path;
// Temp for string length.
size_t length;
// Get module string.
const char* module = location.get_attribute(ImageLocation::ATTRIBUTE_MODULE, strings);
// If module string is not empty string.
if (*module != '\0') {
// Get length of module name.
length = strlen(module);
// Make sure there is no buffer overflow.
guarantee(next - path + length + 2 < max, "buffer overflow");
// Append '/module/'.
*next++ = '/';
strcpy(next, module); next += length;
*next++ = '/';
}
// Get parent (package) string.
const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);
const char* next = ImageStrings::starts_with(path, parent);
// Continue only if a complete match.
if (!next) return false;
// Match up path base.
// If parent string is not empty string.
if (*parent != '\0') {
// Get length of module string.
length = strlen(parent);
// Make sure there is no buffer overflow.
guarantee(next - path + length + 1 < max, "buffer overflow");
// Append 'patent/' .
strcpy(next, parent); next += length;
*next++ = '/';
}
// Get base name string.
const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings);
next = ImageStrings::starts_with(next, base);
// Continue only if a complete match.
if (!next) return false;
// Match up path extension.
// Get length of base name.
length = strlen(base);
// Make sure there is no buffer overflow.
guarantee(next - path + length < max, "buffer overflow");
// Append base name.
strcpy(next, base); next += length;
// Get extension string.
const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);
next = ImageStrings::starts_with(next, extension);
// If extension string is not empty string.
if (*extension != '\0') {
// Get length of extension string.
length = strlen(extension);
// Make sure there is no buffer overflow.
guarantee(next - path + length + 1 < max, "buffer overflow");
// Append '.extension' .
*next++ = '.';
strcpy(next, extension); next += length;
}
// Make sure there is no buffer overflow.
guarantee((size_t)(next - path) < max, "buffer overflow");
// Terminate string.
*next = '\0';
}
// Verify that a found location matches the supplied path (without copying.)
bool ImageFileReader::verify_location(ImageLocation& location, const char* path) const {
// Manage the image string table.
ImageStrings strings(_string_bytes, _header.strings_size(_endian));
// Position to first character of the path string.
const char* next = path;
// Get module name string.
const char* module = location.get_attribute(ImageLocation::ATTRIBUTE_MODULE, strings);
// If module string is not empty.
if (*module != '\0') {
// Compare '/module/' .
if (*next++ != '/') return false;
if (!(next = ImageStrings::starts_with(next, module))) return false;
if (*next++ != '/') return false;
}
// Get parent (package) string
const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);
// If parent string is not empty string.
if (*parent != '\0') {
// Compare 'parent/' .
if (!(next = ImageStrings::starts_with(next, parent))) return false;
if (*next++ != '/') return false;
}
// Get base name string.
const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings);
// Compare with basne name.
if (!(next = ImageStrings::starts_with(next, base))) return false;
// Get extension string.
const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);
// If extension is not empty.
if (*extension != '\0') {
// Compare '.extension' .
if (*next++ != '.') return false;
if (!(next = ImageStrings::starts_with(next, extension))) return false;
}
// True only if complete match and no more characters.
return next && *next == '\0';
return *next == '\0';
}
// Return the resource for the supplied location.
u1* ImageFile::get_resource(ImageLocation& location) const {
// Return the resource data for the supplied location.
void ImageFileReader::get_resource(ImageLocation& location, u1* uncompressed_data) const {
// Retrieve the byte offset and size of the resource.
u8 offset = _index_size + location.get_attribute(ImageLocation::ATTRIBUTE_OFFSET);
u8 size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
u8 offset = location.get_attribute(ImageLocation::ATTRIBUTE_OFFSET);
u8 uncompressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
u8 compressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_COMPRESSED);
u8 read_size = compressed_size ? compressed_size : size;
// Allocate space for the resource.
u1* data = NEW_RESOURCE_ARRAY(u1, read_size);
bool is_read = os::read_at(_fd, data, read_size, offset) == read_size;
guarantee(is_read, "error reading from image or short read");
// If not compressed, just return the data.
if (!compressed_size) {
return data;
}
u1* uncompressed = NEW_RESOURCE_ARRAY(u1, size);
char* msg = NULL;
jboolean res = ClassLoader::decompress(data, compressed_size, uncompressed, size, &msg);
if (!res) warning("decompression failed due to %s\n", msg);
guarantee(res, "decompression failed");
return uncompressed;
}
void ImageFile::get_resource(const char* path, u1*& buffer, u8& size) const {
buffer = NULL;
size = 0;
u1* data = find_location_data(path);
if (data) {
ImageLocation location(data);
if (verify_location(location, path)) {
size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
buffer = get_resource(location);
if (compressed_size != 0) {
ResourceMark rm;
u1* compressed_data;
// If not memory mapped read in bytes.
if (!MemoryMapImage) {
// Allocate buffer for compression.
compressed_data = NEW_RESOURCE_ARRAY(u1, compressed_size);
// Read bytes from offset beyond the image index.
bool is_read = read_at(compressed_data, compressed_size, _index_size + offset);
guarantee(is_read, "error reading from image or short read");
} else {
compressed_data = get_data_address() + offset;
}
// Get image string table.
const ImageStrings strings = get_strings();
// Decompress resource.
ImageDecompressor::decompress_resource(compressed_data, uncompressed_data, uncompressed_size,
&strings, false);
} else {
// Read bytes from offset beyond the image index.
bool is_read = read_at(uncompressed_data, uncompressed_size, _index_size + offset);
guarantee(is_read, "error reading from image or short read");
}
}
GrowableArray<const char*>* ImageFile::packages(const char* name) {
char entry[JVM_MAXPATHLEN];
bool overflow = jio_snprintf(entry, sizeof(entry), "%s/packages.offsets", name) == -1;
guarantee(!overflow, "package name overflow");
u1* buffer;
u8 size;
get_resource(entry, buffer, size);
guarantee(buffer, "missing module packages reource");
ImageStrings strings(_string_bytes, _header._strings_size);
GrowableArray<const char*>* pkgs = new GrowableArray<const char*>();
int count = size / 4;
for (int i = 0; i < count; i++) {
u4 offset = Bytes::get_Java_u4(buffer + (i*4));
const char* p = strings.get(offset);
pkgs->append(p);
}
return pkgs;
}

View File

@ -28,13 +28,15 @@
#include "classfile/classLoader.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "utilities/endian.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
// Image files are an alternate file format for storing classes and resources. The
// goal is to supply file access which is faster and smaller that the jar format.
// It should be noted that unlike jars information stored in an image is in native
// endian format. This allows the image to be memory mapped into memory without
// endian translation. This also means that images are platform dependent.
// goal is to supply file access which is faster and smaller than the jar format.
// It should be noted that unlike jars, information stored in an image is in native
// endian format. This allows the image to be mapped into memory without endian
// translation. This also means that images are platform dependent.
//
// Image files are structured as three sections;
//
@ -42,7 +44,7 @@
// | Header |
// +-----------+
// | |
// | Directory |
// | Index |
// | |
// +-----------+
// | |
@ -60,7 +62,11 @@
// +------------+------------+
// | Major Vers | Minor Vers |
// +------------+------------+
// | Location Count |
// | Flags |
// +-------------------------+
// | Resource Count |
// +-------------------------+
// | Table Length |
// +-------------------------+
// | Attributes Size |
// +-------------------------+
@ -71,23 +77,24 @@
// special file extension.
// Major vers, minor vers - differences in version numbers indicate structural
// changes in the image.
// Location count - number of locations/resources in the file. This count is also
// the length of lookup tables used in the directory.
// Flags - various image wide flags (future).
// Resource count - number of resources in the file.
// Table length - the length of lookup tables used in the index.
// Attributes size - number of bytes in the region used to store location attribute
// streams.
// Strings size - the size of the region used to store strings used by the
// directory and meta data.
// index and meta data.
//
// The directory contains information related to resource lookup. The algorithm
// The index contains information related to resource lookup. The algorithm
// used for lookup is "A Practical Minimal Perfect Hashing Method"
// (http://homepages.dcc.ufmg.br/~nivio/papers/wea05.pdf). Given a path string
// in the form <package>/<base>.<extension> return the resource location
// in the form /<module>/<package>/<base>.<extension> return the resource location
// information;
//
// redirectIndex = hash(path, DEFAULT_SEED) % count;
// redirectIndex = hash(path, DEFAULT_SEED) % table_length;
// redirect = redirectTable[redirectIndex];
// if (redirect == 0) return not found;
// locationIndex = redirect < 0 ? -1 - redirect : hash(path, redirect) % count;
// locationIndex = redirect < 0 ? -1 - redirect : hash(path, redirect) % table_length;
// location = locationTable[locationIndex];
// if (!verify(location, path)) return not found;
// return location;
@ -97,7 +104,7 @@
// other seeds. The verify function guarantees the found resource location is
// indeed the resource we are looking for.
//
// The following is the format of the directory;
// The following is the format of the index;
//
// +-------------------+
// | Redirect Table |
@ -117,54 +124,74 @@
// offsets. Zero indicates not found.
// Attribute Offsets - Array of 32-bit unsigned values representing offsets into
// attribute data. Attribute offsets can be iterated to do a
// full survey of resources in the image.
// full survey of resources in the image. Offset of zero
// indicates no attributes.
// Attribute Data - Bytes representing compact attribute data for locations. (See
// comments in ImageLocation.)
// Strings - Collection of zero terminated UTF-8 strings used by the directory and
// Strings - Collection of zero terminated UTF-8 strings used by the index and
// image meta data. Each string is accessed by offset. Each string is
// unique. Offset zero is reserved for the empty string.
//
// Note that the memory mapped directory assumes 32 bit alignment of the image
// header, the redirect table and the attribute offsets.
// Note that the memory mapped index assumes 32 bit alignment of each component
// in the index.
//
// Endianness of an image.
// An image booted by hotspot is always in native endian. However, it is possible
// to read (by the JDK) in alternate endian format. Primarily, this is during
// cross platform scenarios. Ex, where javac needs to read an embedded image
// to access classes for crossing compilation.
//
class ImageFileReader; // forward declaration
// Manage image file string table.
class ImageStrings {
class ImageStrings VALUE_OBJ_CLASS_SPEC {
private:
// Data bytes for strings.
u1* _data;
// Number of bytes in the string table.
u4 _size;
u1* _data; // Data bytes for strings.
u4 _size; // Number of bytes in the string table.
public:
// Prime used to generate hash for Perfect Hashing.
static const u4 HASH_MULTIPLIER = 0x01000193;
enum {
// Not found result from find routine.
NOT_FOUND = -1,
// Prime used to generate hash for Perfect Hashing.
HASH_MULTIPLIER = 0x01000193
};
ImageStrings(u1* data, u4 size) : _data(data), _size(size) {}
// Return the UTF-8 string beginning at offset.
inline const char* get(u4 offset) const {
assert(offset < _size, "offset exceeds string table size");
guarantee(offset < _size, "offset exceeds string table size");
return (const char*)(_data + offset);
}
// Compute the Perfect Hashing hash code for the supplied string.
// Compute the Perfect Hashing hash code for the supplied UTF-8 string.
inline static u4 hash_code(const char* string) {
return hash_code(string, HASH_MULTIPLIER);
}
// Compute the Perfect Hashing hash code for the supplied string, starting at seed.
static u4 hash_code(const char* string, u4 seed);
static s4 hash_code(const char* string, s4 seed);
// Test to see if string begins with start. If so returns remaining portion
// of string. Otherwise, NULL. Used to test sections of a path without
// copying.
// Match up a string in a perfect hash table. Result still needs validation
// for precise match.
static s4 find(Endian* endian, const char* name, s4* redirect, u4 length);
// Test to see if UTF-8 string begins with the start UTF-8 string. If so,
// return non-NULL address of remaining portion of string. Otherwise, return
// NULL. Used to test sections of a path without copying from image string
// table.
static const char* starts_with(const char* string, const char* start);
// Test to see if UTF-8 string begins with start char. If so, return non-NULL
// address of remaining portion of string. Otherwise, return NULL. Used
// to test a character of a path without copying.
inline static const char* starts_with(const char* string, const char ch) {
return *string == ch ? string + 1 : NULL;
}
};
// Manage image file location attribute streams. Within an image, a location's
// Manage image file location attribute data. Within an image, a location's
// attributes are compressed into a stream of bytes. An attribute stream is
// composed of individual attribute sequences. Each attribute sequence begins with
// a header byte containing the attribute 'kind' (upper 5 bits of header) and the
@ -188,7 +215,7 @@ public:
// stream.
// - ATTRIBUTE_OFFSET represents the number of bytes from the beginning of the region
// storing the resources. Thus, in an image this represents the number of bytes
// after the directory.
// after the index.
// - Currently, compressed resources are represented by having a non-zero
// ATTRIBUTE_COMPRESSED value. This represents the number of bytes stored in the
// image, and the value of ATTRIBUTE_UNCOMPRESSED represents number of bytes of the
@ -198,17 +225,19 @@ public:
// represented differently.
// - Package strings include trailing slash and extensions include prefix period.
//
class ImageLocation {
class ImageLocation VALUE_OBJ_CLASS_SPEC {
public:
// Attribute kind enumeration.
static const u1 ATTRIBUTE_END = 0; // End of attribute stream marker
static const u1 ATTRIBUTE_BASE = 1; // String table offset of resource path base
static const u1 ATTRIBUTE_PARENT = 2; // String table offset of resource path parent
static const u1 ATTRIBUTE_EXTENSION = 3; // String table offset of resource path extension
static const u1 ATTRIBUTE_OFFSET = 4; // Container byte offset of resource
static const u1 ATTRIBUTE_COMPRESSED = 5; // In image byte size of the compressed resource
static const u1 ATTRIBUTE_UNCOMPRESSED = 6; // In memory byte size of the uncompressed resource
static const u1 ATTRIBUTE_COUNT = 7; // Number of attribute kinds
enum {
ATTRIBUTE_END, // End of attribute stream marker
ATTRIBUTE_MODULE, // String table offset of module name
ATTRIBUTE_PARENT, // String table offset of resource path parent
ATTRIBUTE_BASE, // String table offset of resource path base
ATTRIBUTE_EXTENSION, // String table offset of resource path extension
ATTRIBUTE_OFFSET, // Container byte offset of resource
ATTRIBUTE_COMPRESSED, // In image byte size of the compressed resource
ATTRIBUTE_UNCOMPRESSED, // In memory byte size of the uncompressed resource
ATTRIBUTE_COUNT // Number of attribute kinds
};
private:
// Values of inflated attributes.
@ -222,30 +251,43 @@ private:
// Return the attribute kind.
inline static u1 attribute_kind(u1 data) {
u1 kind = data >> 3;
assert(kind < ATTRIBUTE_COUNT, "invalid attribute kind");
guarantee(kind < ATTRIBUTE_COUNT, "invalid attribute kind");
return kind;
}
// Return the attribute length.
inline static u8 attribute_value(u1* data, u1 n) {
assert(0 < n && n <= 8, "invalid attribute value length");
guarantee(0 < n && n <= 8, "invalid attribute value length");
u8 value = 0;
// Most significant bytes first.
for (u1 i = 0; i < n; i++) {
value <<= 8;
value |= data[i];
}
return value;
}
public:
ImageLocation(u1* data);
ImageLocation() {
clear_data();
}
ImageLocation(u1* data) {
clear_data();
set_data(data);
}
// Inflates the attribute stream into individual values stored in the long
// array _attributes. This allows an attribute value to be quickly accessed by
// direct indexing. Unspecified values default to zero.
void set_data(u1* data);
// Zero all attribute values.
void clear_data();
// Retrieve an attribute value from the inflated array.
inline u8 get_attribute(u1 kind) const {
assert(ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT, "invalid attribute kind");
guarantee(ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT, "invalid attribute kind");
return _attributes[kind];
}
@ -255,89 +297,306 @@ public:
}
};
// Manage the image file.
class ImageFile: public CHeapObj<mtClass> {
private:
// Image file marker.
static const u4 IMAGE_MAGIC = 0xCAFEDADA;
// Image file major version number.
static const u2 MAJOR_VERSION = 0;
// Image file minor version number.
static const u2 MINOR_VERSION = 1;
struct ImageHeader {
u4 _magic; // Image file marker
u2 _major_version; // Image file major version number
u2 _minor_version; // Image file minor version number
u4 _location_count; // Number of locations managed in index.
u4 _locations_size; // Number of bytes in attribute table.
u4 _strings_size; // Number of bytes in string table.
//
// NOTE: needs revision.
// Each loader requires set of module meta data to identify which modules and
// packages are managed by that loader. Currently, there is one image file per
// builtin loader, so only one module meta data resource per file.
//
// Each element in the module meta data is a native endian 4 byte integer. Note
// that entries with zero offsets for string table entries should be ignored (
// padding for hash table lookup.)
//
// Format:
// Count of package to module entries
// Count of module to package entries
// Perfect Hash redirect table[Count of package to module entries]
// Package to module entries[Count of package to module entries]
// Offset to package name in string table
// Offset to module name in string table
// Perfect Hash redirect table[Count of module to package entries]
// Module to package entries[Count of module to package entries]
// Offset to module name in string table
// Count of packages in module
// Offset to first package in packages table
// Packages[]
// Offset to package name in string table
//
// Manage the image module meta data.
class ImageModuleData : public CHeapObj<mtClass> {
class Header VALUE_OBJ_CLASS_SPEC {
private:
u4 _ptm_count; // Count of package to module entries
u4 _mtp_count; // Count of module to package entries
public:
inline u4 ptm_count(Endian* endian) const { return endian->get(_ptm_count); }
inline u4 mtp_count(Endian* endian) const { return endian->get(_mtp_count); }
};
char* _name; // Name of image
int _fd; // File descriptor
bool _memory_mapped; // Is file memory mapped
ImageHeader _header; // Image header
u8 _index_size; // Total size of index
u1* _index_data; // Raw index data
s4* _redirect_table; // Perfect hash redirect table
u4* _offsets_table; // Location offset table
u1* _location_bytes; // Location attributes
u1* _string_bytes; // String table
// Hashtable entry
class HashData VALUE_OBJ_CLASS_SPEC {
private:
u4 _name_offset; // Name offset in string table
public:
inline s4 name_offset(Endian* endian) const { return endian->get(_name_offset); }
};
// Package to module hashtable entry
class PTMData : public HashData {
private:
u4 _module_name_offset; // Module name offset in string table
public:
inline s4 module_name_offset(Endian* endian) const { return endian->get(_module_name_offset); }
};
// Module to package hashtable entry
class MTPData : public HashData {
private:
u4 _package_count; // Number of packages in module
u4 _package_offset; // Offset in package list
public:
inline u4 package_count(Endian* endian) const { return endian->get(_package_count); }
inline u4 package_offset(Endian* endian) const { return endian->get(_package_offset); }
};
const ImageFileReader* _image_file; // Source image file
Endian* _endian; // Endian handler
ImageStrings _strings; // Image file strings
u1* _data; // Module data resource data
u8 _data_size; // Size of resource data
Header* _header; // Module data header
s4* _ptm_redirect; // Package to module hashtable redirect
PTMData* _ptm_data; // Package to module data
s4* _mtp_redirect; // Module to packages hashtable redirect
MTPData* _mtp_data; // Module to packages data
s4* _mtp_packages; // Package data (name offsets)
// Return a string from the string table.
inline const char* get_string(u4 offset) {
return _strings.get(offset);
}
inline u4 mtp_package(u4 index) {
return _endian->get(_mtp_packages[index]);
}
public:
ImageModuleData(const ImageFileReader* image_file, const char* module_data_name);
~ImageModuleData();
// Return the name of the module data resource.
static void module_data_name(char* buffer, const char* image_file_name);
// Return the module in which a package resides. Returns NULL if not found.
const char* package_to_module(const char* package_name);
// Returns all the package names in a module. Returns NULL if module not found.
GrowableArray<const char*>* module_to_packages(const char* module_name);
};
// Image file header, starting at offset 0.
class ImageHeader VALUE_OBJ_CLASS_SPEC {
private:
u4 _magic; // Image file marker
u4 _version; // Image file major version number
u4 _flags; // Image file flags
u4 _resource_count; // Number of resources in file
u4 _table_length; // Number of slots in index tables
u4 _locations_size; // Number of bytes in attribute table
u4 _strings_size; // Number of bytes in string table
public:
u4 magic() const { return _magic; }
u4 magic(Endian* endian) const { return endian->get(_magic); }
void set_magic(Endian* endian, u4 magic) { return endian->set(_magic, magic); }
u4 major_version(Endian* endian) const { return endian->get(_version) >> 16; }
u4 minor_version(Endian* endian) const { return endian->get(_version) & 0xFFFF; }
void set_version(Endian* endian, u4 major_version, u4 minor_version) {
return endian->set(_version, major_version << 16 | minor_version);
}
u4 flags(Endian* endian) const { return endian->get(_flags); }
void set_flags(Endian* endian, u4 value) { return endian->set(_flags, value); }
u4 resource_count(Endian* endian) const { return endian->get(_resource_count); }
void set_resource_count(Endian* endian, u4 count) { return endian->set(_resource_count, count); }
u4 table_length(Endian* endian) const { return endian->get(_table_length); }
void set_table_length(Endian* endian, u4 count) { return endian->set(_table_length, count); }
u4 locations_size(Endian* endian) const { return endian->get(_locations_size); }
void set_locations_size(Endian* endian, u4 size) { return endian->set(_locations_size, size); }
u4 strings_size(Endian* endian) const { return endian->get(_strings_size); }
void set_strings_size(Endian* endian, u4 size) { return endian->set(_strings_size, size); }
};
// Max path length limit independent of platform. Windows max path is 1024,
// other platforms use 4096. The JCK fails several tests when 1024 is used.
#define IMAGE_MAX_PATH 4096
// Manage the image file.
// ImageFileReader manages the content of an image file.
// Initially, the header of the image file is read for validation. If valid,
// values in the header are used calculate the size of the image index. The
// index is then memory mapped to allow load on demand and sharing. The
// -XX:+MemoryMapImage flag determines if the entire file is loaded (server use.)
// An image can be used by Hotspot and multiple reference points in the JDK, thus
// it is desirable to share a reader. To accomodate sharing, a share table is
// defined (see ImageFileReaderTable in imageFile.cpp) To track the number of
// uses, ImageFileReader keeps a use count (_use). Use is incremented when
// 'opened' by reference point and decremented when 'closed'. Use of zero
// leads the ImageFileReader to be actually closed and discarded.
class ImageFileReader : public CHeapObj<mtClass> {
private:
// Manage a number of image files such that an image can be shared across
// multiple uses (ex. loader.)
static GrowableArray<ImageFileReader*>* _reader_table;
char* _name; // Name of image
s4 _use; // Use count
int _fd; // File descriptor
Endian* _endian; // Endian handler
u8 _file_size; // File size in bytes
ImageHeader _header; // Image header
size_t _index_size; // Total size of index
u1* _index_data; // Raw index data
s4* _redirect_table; // Perfect hash redirect table
u4* _offsets_table; // Location offset table
u1* _location_bytes; // Location attributes
u1* _string_bytes; // String table
ImageFileReader(const char* name, bool big_endian);
~ImageFileReader();
// Compute number of bytes in image file index.
inline u8 index_size() {
return sizeof(ImageHeader) +
_header._location_count * sizeof(u4) * 2 +
_header._locations_size +
_header._strings_size;
table_length() * sizeof(u4) * 2 + locations_size() + strings_size();
}
public:
ImageFile(const char* name);
~ImageFile();
enum {
// Image file marker.
IMAGE_MAGIC = 0xCAFEDADA,
// Endian inverted Image file marker.
IMAGE_MAGIC_INVERT = 0xDADAFECA,
// Image file major version number.
MAJOR_VERSION = 1,
// Image file minor version number.
MINOR_VERSION = 0
};
// Open image file for access.
// Open an image file, reuse structure if file already open.
static ImageFileReader* open(const char* name, bool big_endian = Endian::is_big_endian());
// Close an image file if the file is not in use elsewhere.
static void close(ImageFileReader *reader);
// Return an id for the specifed ImageFileReader.
static u8 readerToID(ImageFileReader *reader);
// Validate the image id.
static bool idCheck(u8 id);
// Return an id for the specifed ImageFileReader.
static ImageFileReader* idToReader(u8 id);
// Open image file for read access.
bool open();
// Close image file.
void close();
// Read directly from the file.
bool read_at(u1* data, u8 size, u8 offset) const;
inline Endian* endian() const { return _endian; }
// Retrieve name of image file.
inline const char* name() const {
return _name;
}
// Retrieve size of image file.
inline u8 file_size() const {
return _file_size;
}
// Return first address of index data.
inline u1* get_index_address() const {
return _index_data;
}
// Return first address of resource data.
inline u1* get_data_address() const {
return _index_data + _index_size;
}
// Get the size of the index data.
size_t get_index_size() const {
return _index_size;
}
inline u4 table_length() const {
return _header.table_length(_endian);
}
inline u4 locations_size() const {
return _header.locations_size(_endian);
}
inline u4 strings_size()const {
return _header.strings_size(_endian);
}
inline u4* offsets_table() const {
return _offsets_table;
}
// Increment use count.
inline void inc_use() {
_use++;
}
// Decrement use count.
inline bool dec_use() {
return --_use == 0;
}
// Return a string table accessor.
inline const ImageStrings get_strings() const {
return ImageStrings(_string_bytes, _header._strings_size);
return ImageStrings(_string_bytes, _header.strings_size(_endian));
}
// Return number of locations in image file index.
inline u4 get_location_count() const {
return _header._location_count;
}
// Return location attribute stream for location i.
inline u1* get_location_data(u4 i) const {
u4 offset = _offsets_table[i];
// Return location attribute stream at offset.
inline u1* get_location_offset_data(u4 offset) const {
guarantee((u4)offset < _header.locations_size(_endian),
"offset exceeds location attributes size");
return offset != 0 ? _location_bytes + offset : NULL;
}
// Return the attribute stream for a named resourced.
u1* find_location_data(const char* path) const;
// Return location attribute stream for location i.
inline u1* get_location_data(u4 index) const {
guarantee((u4)index < _header.table_length(_endian),
"index exceeds location count");
u4 offset = _endian->get(_offsets_table[index]);
return get_location_offset_data(offset);
}
// Find the location attributes associated with the path. Returns true if
// the location is found, false otherwise.
bool find_location(const char* path, ImageLocation& location) const;
// Assemble the location path.
void location_path(ImageLocation& location, char* path, size_t max) const;
// Verify that a found location matches the supplied path.
bool verify_location(ImageLocation& location, const char* path) const;
// Return the resource for the supplied location info.
u1* get_resource(ImageLocation& location) const;
// Return the resource associated with the path else NULL if not found.
void get_resource(const char* path, u1*& buffer, u8& size) const;
// Return an array of packages for a given module
GrowableArray<const char*>* packages(const char* name);
// Return the resource for the supplied path.
void get_resource(ImageLocation& location, u1* uncompressed_data) const;
};
#endif // SHARE_VM_CLASSFILE_IMAGEFILE_HPP

View File

@ -57,6 +57,8 @@
# include "classfile/classFileParser.hpp"
# include "classfile/classFileStream.hpp"
# include "classfile/classLoader.hpp"
# include "classfile/imageDecompressor.hpp"
# include "classfile/imageFile.hpp"
# include "classfile/javaClasses.hpp"
# include "classfile/symbolTable.hpp"
# include "classfile/systemDictionary.hpp"
@ -229,6 +231,7 @@
# include "utilities/constantTag.hpp"
# include "utilities/copy.hpp"
# include "utilities/debug.hpp"
# include "utilities/endian.hpp"
# include "utilities/exceptions.hpp"
# include "utilities/globalDefinitions.hpp"
# include "utilities/growableArray.hpp"

View File

@ -24,6 +24,8 @@
#include "precompiled.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/imageDecompressor.hpp"
#include "classfile/imageFile.hpp"
#include "classfile/javaAssertions.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/stringTable.hpp"
@ -69,6 +71,7 @@
#include "utilities/copy.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/endian.hpp"
#include "utilities/events.hpp"
#include "utilities/histogram.hpp"
#include "utilities/macros.hpp"
@ -3665,3 +3668,244 @@ JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t i
info->is_attachable = AttachListener::is_attach_supported();
}
JVM_END
// jdk.internal.jimage /////////////////////////////////////////////////////////
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
// Java entry to open an image file for sharing.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(jlong,
JVM_ImageOpen(JNIEnv *env, const char *nativePath, jboolean big_endian)) {
JVMWrapper("JVM_ImageOpen");
// Open image file for reading.
ImageFileReader* reader = ImageFileReader::open(nativePath, big_endian != JNI_FALSE);
// Return image ID as a jlong.
return ImageFileReader::readerToID(reader);
}
JVM_END
// Java entry for closing a shared image file.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(void,
JVM_ImageClose(JNIEnv *env, jlong id)) {
JVMWrapper("JVM_ImageClose");
// Convert image ID to image reader structure.
ImageFileReader* reader = ImageFileReader::idToReader(id);
// If valid reader the close.
if (reader != NULL) {
ImageFileReader::close(reader);
}
}
JVM_END
// Java entry for accessing the base address of the image index.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(jlong,
JVM_ImageGetIndexAddress(JNIEnv *env, jlong id)) {
JVMWrapper("JVM_ImageGetIndexAddress");
// Convert image ID to image reader structure.
ImageFileReader* reader = ImageFileReader::idToReader(id);
// If valid reader return index base address (as jlong) else zero.
return reader != NULL ? (jlong)reader->get_index_address() : 0L;
}
JVM_END
// Java entry for accessing the base address of the image data.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(jlong,
JVM_ImageGetDataAddress(JNIEnv *env, jlong id)) {
JVMWrapper("JVM_ImageGetDataAddress");
// Convert image ID to image reader structure.
ImageFileReader* reader = ImageFileReader::idToReader(id);
// If valid reader return data base address (as jlong) else zero.
return MemoryMapImage && reader != NULL ? (jlong)reader->get_data_address() : 0L;
}
JVM_END
// Java entry for reading an uncompressed resource from the image.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(jboolean,
JVM_ImageRead(JNIEnv *env, jlong id, jlong offset,
unsigned char* uncompressedAddress, jlong uncompressed_size)) {
JVMWrapper("JVM_ImageRead");
// Convert image ID to image reader structure.
ImageFileReader* reader = ImageFileReader::idToReader(id);\
// If not a valid reader the fail the read.
if (reader == NULL) return false;
// Get the file offset of resource data.
u8 file_offset = reader->get_index_size() + offset;
// Check validity of arguments.
if (offset < 0 ||
uncompressed_size < 0 ||
file_offset > reader->file_size() - uncompressed_size) {
return false;
}
// Read file content into buffer.
return (jboolean)reader->read_at((u1*)uncompressedAddress, uncompressed_size,
file_offset);
}
JVM_END
// Java entry for reading a compressed resource from the image.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(jboolean,
JVM_ImageReadCompressed(JNIEnv *env,
jlong id, jlong offset,
unsigned char* compressedAddress, jlong compressed_size,
unsigned char* uncompressedAddress, jlong uncompressed_size)) {
JVMWrapper("JVM_ImageReadCompressed");
// Convert image ID to image reader structure.
ImageFileReader* reader = ImageFileReader::idToReader(id);
// If not a valid reader the fail the read.
if (reader == NULL) return false;
// Get the file offset of resource data.
u8 file_offset = reader->get_index_size() + offset;
// Check validity of arguments.
if (offset < 0 ||
compressed_size < 0 ||
uncompressed_size < 0 ||
file_offset > reader->file_size() - compressed_size) {
return false;
}
// Read file content into buffer.
bool is_read = reader->read_at(compressedAddress, compressed_size,
file_offset);
// If successfully read then decompress.
if (is_read) {
const ImageStrings strings = reader->get_strings();
ImageDecompressor::decompress_resource(compressedAddress, uncompressedAddress,
uncompressed_size, &strings, true);
}
return (jboolean)is_read;
}
JVM_END
// Java entry for retrieving UTF-8 bytes from image string table.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(const char*, JVM_ImageGetStringBytes(JNIEnv *env, jlong id, jint offset)) {
JVMWrapper("JVM_ImageGetStringBytes");
// Convert image ID to image reader structure.
ImageFileReader* reader = ImageFileReader::idToReader(id);
// Fail if not valid reader.
if (reader == NULL) return NULL;
// Manage image string table.
ImageStrings strings = reader->get_strings();
// Retrieve string adrress from table.
const char* data = strings.get(offset);
return data;
}
JVM_END
// Utility function to copy location information into a jlong array.
// WARNING: This function is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
static void image_expand_location(JNIEnv *env, jlong* rawAttributes, ImageLocation& location) {
// Copy attributes from location.
for (int kind = ImageLocation::ATTRIBUTE_END + 1;
kind < ImageLocation::ATTRIBUTE_COUNT;
kind++) {
rawAttributes[kind] = location.get_attribute(kind);
}
}
// Java entry for retrieving location attributes for attribute offset.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(jlong*, JVM_ImageGetAttributes(JNIEnv *env, jlong* rawAttributes, jlong id, jint offset)) {
JVMWrapper("JVM_ImageGetAttributes");
// Convert image ID to image reader structure.
ImageFileReader* reader = ImageFileReader::idToReader(id);
// Fail if not valid reader.
if (reader == NULL) return NULL;
// Retrieve first byte address of resource's location attribute stream.
u1* data = reader->get_location_offset_data(offset);
// Fail if not valid offset.
if (data == NULL) return NULL;
// Expand stream into array.
ImageLocation location(data);
image_expand_location(env, rawAttributes, location);
return rawAttributes;
}
JVM_END
// Java entry for retrieving location attributes count for attribute offset.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(jsize, JVM_ImageGetAttributesCount(JNIEnv *env)) {
JVMWrapper("JVM_ImageGetAttributesCount");
return ImageLocation::ATTRIBUTE_COUNT;
}
JVM_END
// Java entry for retrieving location attributes for named resource.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(jlong*,
JVM_ImageFindAttributes(JNIEnv *env, jlong* rawAttributes, jbyte* rawBytes, jsize size, jlong id)) {
JVMWrapper("JVM_ImageFindAttributes");
// Mark for temporary buffers.
ResourceMark rm;
// Convert image ID to image reader structure.
ImageFileReader* reader = ImageFileReader::idToReader(id);
// Fail if not valid reader.
if (reader == NULL) return NULL;
// Convert byte array to a cstring.
char* path = NEW_RESOURCE_ARRAY(char, size + 1);
memcpy(path, rawBytes, size);
path[size] = '\0';
// Locate resource location data.
ImageLocation location;
bool found = reader->find_location(path, location);
// Resource not found.
if (!found) return NULL;
// Expand stream into array.
image_expand_location(env, rawAttributes, location);
return rawAttributes;
}
JVM_END
// Java entry for retrieving all the attribute stream offsets from an image.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(jint*, JVM_ImageAttributeOffsets(JNIEnv *env, jint* rawOffsets, unsigned int length, jlong id)) {
JVMWrapper("JVM_ImageAttributeOffsets");
// Convert image ID to image reader structure.
ImageFileReader* reader = ImageFileReader::idToReader(id);
// Fail if not valid reader.
if (reader == NULL) return NULL;
// Determine endian for reader.
Endian* endian = reader->endian();
// Get base address of attribute stream offsets table.
u4* offsets_table = reader->offsets_table();
// Allocate int array result.
// Copy values to result (converting endian.)
for (u4 i = 0; i < length; i++) {
rawOffsets[i] = endian->get(offsets_table[i]);
}
return rawOffsets;
}
JVM_END
// Java entry for retrieving all the attribute stream offsets length from an image.
// WARNING: This API is experimental and temporary during JDK 9 development
// cycle. It will not be supported in the eventual JDK 9 release.
JVM_ENTRY(unsigned int, JVM_ImageAttributeOffsetsLength(JNIEnv *env, jlong id)) {
JVMWrapper("JVM_ImageAttributeOffsetsLength");
// Convert image ID to image reader structure.
ImageFileReader* reader = ImageFileReader::idToReader(id);
// Fail if not valid reader.
if (reader == NULL) return 0;
// Get perfect hash table length.
u4 length = reader->table_length();
return (jint) length;
}
JVM_END

View File

@ -571,6 +571,52 @@ JVM_AssertionStatusDirectives(JNIEnv *env, jclass unused);
JNIEXPORT jboolean JNICALL
JVM_SupportsCX8(void);
/*
* jdk.internal.jimage
* WARNING: This API is experimental and temporary during JDK 9 development
* cycle. It will not be supported in the eventual JDK 9 release.
*/
JNIEXPORT jlong JNICALL
JVM_ImageOpen(JNIEnv *env, const char *nativePath, jboolean big_endian);
JNIEXPORT void JNICALL
JVM_ImageClose(JNIEnv *env, jlong id);
JNIEXPORT jlong JNICALL
JVM_ImageGetIndexAddress(JNIEnv *env, jlong id);
JNIEXPORT jlong JNICALL
JVM_ImageGetDataAddress(JNIEnv *env,jlong id);
JNIEXPORT jboolean JNICALL
JVM_ImageRead(JNIEnv *env, jlong id, jlong offset,
unsigned char* uncompressedAddress, jlong uncompressed_size);
JNIEXPORT jboolean JNICALL
JVM_ImageReadCompressed(JNIEnv *env, jlong id, jlong offset,
unsigned char* compressedBuffer, jlong compressed_size,
unsigned char* uncompressedBuffer, jlong uncompressed_size);
JNIEXPORT const char* JNICALL
JVM_ImageGetStringBytes(JNIEnv *env, jlong id, jint offset);
JNIEXPORT jlong* JNICALL
JVM_ImageGetAttributes(JNIEnv *env, jlong* rawAttributes, jlong id, jint offset);
JNIEXPORT jsize JNICALL
JVM_ImageGetAttributesCount(JNIEnv *env);
JNIEXPORT jlong* JNICALL
JVM_ImageFindAttributes(JNIEnv *env, jlong* rawAttributes, jbyte* rawBytes, jsize size, jlong id);
JNIEXPORT jint* JNICALL
JVM_ImageAttributeOffsets(JNIEnv *env, jint* rawOffsets, unsigned int length, jlong id);
JNIEXPORT unsigned int JNICALL
JVM_ImageAttributeOffsetsLength(JNIEnv *env, jlong id);
/*************************************************************************
PART 2: Support for the Verifier and Class File Format Checker
************************************************************************/

View File

@ -27,6 +27,7 @@
#include <new>
#include "classfile/classLoaderData.hpp"
#include "classfile/imageFile.hpp"
#include "classfile/stringTable.hpp"
#include "code/codeCache.hpp"
#include "jvmtifiles/jvmtiEnv.hpp"
@ -1125,6 +1126,132 @@ WB_ENTRY(jlong, WB_MetaspaceCapacityUntilGC(JNIEnv* env, jobject wb))
return (jlong) MetaspaceGC::capacity_until_GC();
WB_END
WB_ENTRY(jboolean, WB_ReadImageFile(JNIEnv* env, jobject wb, jstring imagefile))
const char* filename = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(imagefile));
return ImageFileReader::open(filename) != NULL;
WB_END
WB_ENTRY(jlong, WB_imageOpenImage(JNIEnv *env, jobject wb, jstring path, jboolean big_endian))
ThreadToNativeFromVM ttn(thread);
const char *nativePath = env->GetStringUTFChars(path, NULL);
jlong ret = JVM_ImageOpen(env, nativePath, big_endian);
env->ReleaseStringUTFChars(path, nativePath);
return ret;
WB_END
WB_ENTRY(void, WB_imageCloseImage(JNIEnv *env, jobject wb, jlong id))
ThreadToNativeFromVM ttn(thread);
JVM_ImageClose(env, id);
WB_END
WB_ENTRY(jlong, WB_imageGetIndexAddress(JNIEnv *env, jobject wb, jlong id))
ThreadToNativeFromVM ttn(thread);
return JVM_ImageGetIndexAddress(env, id);
WB_END
WB_ENTRY(jlong, WB_imageGetDataAddress(JNIEnv *env, jobject wb, jlong id))
ThreadToNativeFromVM ttn(thread);
return JVM_ImageGetDataAddress(env, id);
WB_END
WB_ENTRY(jboolean, WB_imageRead(JNIEnv *env, jobject wb, jlong id, jlong offset, jobject uncompressedBuffer, jlong uncompressed_size))
ThreadToNativeFromVM ttn(thread);
if (uncompressedBuffer == NULL) {
return JNI_FALSE;
}
unsigned char* uncompressedAddress =
(unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer);
return JVM_ImageRead(env, id, offset, uncompressedAddress, uncompressed_size);
WB_END
WB_ENTRY(jboolean, WB_imageReadCompressed(JNIEnv *env, jobject wb, jlong id, jlong offset, jobject compressedBuffer, jlong compressed_size, jobject uncompressedBuffer, jlong uncompressed_size))
ThreadToNativeFromVM ttn(thread);
if (uncompressedBuffer == NULL || compressedBuffer == NULL) {
return false;
}
// Get address of read direct buffer.
unsigned char* compressedAddress =
(unsigned char*) env->GetDirectBufferAddress(compressedBuffer);
// Get address of decompression direct buffer.
unsigned char* uncompressedAddress =
(unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer);
return JVM_ImageReadCompressed(env, id, offset, compressedAddress, compressed_size, uncompressedAddress, uncompressed_size);
WB_END
WB_ENTRY(jbyteArray, WB_imageGetStringBytes(JNIEnv *env, jobject wb, jlong id, jlong offset))
ThreadToNativeFromVM ttn(thread);
const char* data = JVM_ImageGetStringBytes(env, id, offset);
// Determine String length.
size_t size = strlen(data);
// Allocate byte array.
jbyteArray byteArray = env->NewByteArray((jsize) size);
// Get array base address.
jbyte* rawBytes = env->GetByteArrayElements(byteArray, NULL);
// Copy bytes from image string table.
memcpy(rawBytes, data, size);
// Release byte array base address.
env->ReleaseByteArrayElements(byteArray, rawBytes, 0);
return byteArray;
WB_END
WB_ENTRY(jlong, WB_imageGetStringsSize(JNIEnv *env, jobject wb, jlong id))
ImageFileReader* reader = ImageFileReader::idToReader(id);
return reader? reader->strings_size() : 0L;
WB_END
WB_ENTRY(jlongArray, WB_imageGetAttributes(JNIEnv *env, jobject wb, jlong id, jint offset))
ThreadToNativeFromVM ttn(thread);
// Allocate a jlong large enough for all location attributes.
jlongArray attributes = env->NewLongArray(JVM_ImageGetAttributesCount(env));
// Get base address for jlong array.
jlong* rawAttributes = env->GetLongArrayElements(attributes, NULL);
jlong* ret = JVM_ImageGetAttributes(env, rawAttributes, id, offset);
// Release jlong array base address.
env->ReleaseLongArrayElements(attributes, rawAttributes, 0);
return ret == NULL ? NULL : attributes;
WB_END
WB_ENTRY(jlongArray, WB_imageFindAttributes(JNIEnv *env, jobject wb, jlong id, jbyteArray utf8))
ThreadToNativeFromVM ttn(thread);
// Allocate a jlong large enough for all location attributes.
jlongArray attributes = env->NewLongArray(JVM_ImageGetAttributesCount(env));
// Get base address for jlong array.
jlong* rawAttributes = env->GetLongArrayElements(attributes, NULL);
jsize size = env->GetArrayLength(utf8);
jbyte* rawBytes = env->GetByteArrayElements(utf8, NULL);
jlong* ret = JVM_ImageFindAttributes(env, rawAttributes, rawBytes, size, id);
env->ReleaseByteArrayElements(utf8, rawBytes, 0);
env->ReleaseLongArrayElements(attributes, rawAttributes, 0);
return ret == NULL ? NULL : attributes;
WB_END
WB_ENTRY(jintArray, WB_imageAttributeOffsets(JNIEnv *env, jobject wb, jlong id))
ThreadToNativeFromVM ttn(thread);
unsigned int length = JVM_ImageAttributeOffsetsLength(env, id);
if (length == 0) {
return NULL;
}
jintArray offsets = env->NewIntArray(length);
// Get base address of result.
jint* rawOffsets = env->GetIntArrayElements(offsets, NULL);
jint* ret = JVM_ImageAttributeOffsets(env, rawOffsets, length, id);
// Release result base address.
env->ReleaseIntArrayElements(offsets, rawOffsets, 0);
return ret == NULL ? NULL : offsets;
WB_END
WB_ENTRY(jint, WB_imageGetIntAtAddress(JNIEnv *env, jobject wb, jlong address, jint offset, jboolean big_endian))
unsigned char* arr = (unsigned char*) address + offset;
jint uraw;
if (big_endian) {
uraw = arr[0] << 24 | arr[1]<<16 | (arr[2]<<8) | arr[3];
} else {
uraw = arr[0] | arr[1]<<8 | (arr[2]<<16) | arr[3]<<24;
}
return uraw;
WB_END
WB_ENTRY(void, WB_AssertMatchingSafepointCalls(JNIEnv* env, jobject o, jboolean mutexSafepointValue, jboolean attemptedNoSafepointValue))
Monitor::SafepointCheckRequired sfpt_check_required = mutexSafepointValue ?
Monitor::_safepoint_check_always :
@ -1428,8 +1555,23 @@ static JNINativeMethod methods[] = {
{CC"getCodeBlob", CC"(J)[Ljava/lang/Object;",(void*)&WB_GetCodeBlob },
{CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize },
{CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize },
{CC"readImageFile", CC"(Ljava/lang/String;)Z", (void*)&WB_ReadImageFile },
{CC"imageOpenImage", CC"(Ljava/lang/String;Z)J",(void*)&WB_imageOpenImage },
{CC"imageCloseImage", CC"(J)V", (void*)&WB_imageCloseImage },
{CC"imageGetIndexAddress",CC"(J)J", (void*)&WB_imageGetIndexAddress},
{CC"imageGetDataAddress",CC"(J)J", (void*)&WB_imageGetDataAddress},
{CC"imageRead", CC"(JJLjava/nio/ByteBuffer;J)Z",
(void*)&WB_imageRead },
{CC"imageReadCompressed",CC"(JJLjava/nio/ByteBuffer;JLjava/nio/ByteBuffer;J)Z",
(void*)&WB_imageReadCompressed},
{CC"imageGetStringBytes",CC"(JI)[B", (void*)&WB_imageGetStringBytes},
{CC"imageGetStringsSize",CC"(J)J", (void*)&WB_imageGetStringsSize},
{CC"imageGetAttributes", CC"(JI)[J", (void*)&WB_imageGetAttributes},
{CC"imageFindAttributes",CC"(J[B)[J", (void*)&WB_imageFindAttributes},
{CC"imageAttributeOffsets",CC"(J)[I", (void*)&WB_imageAttributeOffsets},
{CC"imageGetIntAtAddress",CC"(JIZ)I", (void*)&WB_imageGetIntAtAddress},
{CC"assertMatchingSafepointCalls", CC"(ZZ)V", (void*)&WB_AssertMatchingSafepointCalls },
{CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated },
{CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated },
{CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint },
{CC"getMethodBooleanOption",
CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/Boolean;",

View File

@ -1582,6 +1582,9 @@ void Arguments::set_ergonomics_flags() {
// in vm_version initialization code.
#endif // _LP64
#endif // !ZERO
// Set up runtime image flags.
set_runtime_image_flags();
}
void Arguments::set_parallel_gc_flags() {
@ -1837,6 +1840,16 @@ void Arguments::set_heap_size() {
}
}
// Set up runtime image flags
void Arguments::set_runtime_image_flags() {
#ifdef _LP64
// Memory map image file by default on 64 bit machines.
if (FLAG_IS_DEFAULT(MemoryMapImage)) {
FLAG_SET_ERGO(bool, MemoryMapImage, true);
}
#endif
}
// This must be called after ergonomics.
void Arguments::set_bytecode_flags() {
if (!RewriteBytecodes) {

View File

@ -347,6 +347,8 @@ class Arguments : AllStatic {
static julong limit_by_allocatable_memory(julong size);
// Setup heap size
static void set_heap_size();
// Set up runtime image flags
static void set_runtime_image_flags();
// Based on automatic selection criteria, should the
// low pause collector be used.
static bool should_auto_select_low_pause_collector();

View File

@ -1093,6 +1093,9 @@ public:
product(bool, AlwaysRestoreFPU, false, \
"Restore the FPU control word after every JNI call (expensive)") \
\
product(bool, MemoryMapImage, false, \
"Memory map entire runtime image") \
\
diagnostic(bool, PrintCompilation2, false, \
"Print additional statistics per compilation") \
\

View File

@ -82,6 +82,7 @@ void stubRoutines_init2(); // note: StubRoutines need 2-phase init
// during VM shutdown
void perfMemory_exit();
void ostream_exit();
bool image_decompressor_init();
void vm_init_globals() {
check_ThreadShadow();
@ -115,6 +116,9 @@ jint init_globals() {
templateTable_init();
InterfaceSupport_init();
SharedRuntime::generate_stubs();
if (!image_decompressor_init()) {
return JNI_ERR;
}
universe2_init(); // dependent on codeCache_init and stubRoutines_init1
referenceProcessor_init();
jni_handles_init();

View File

@ -100,6 +100,8 @@ Mutex* ProfilePrint_lock = NULL;
Mutex* ExceptionCache_lock = NULL;
Monitor* ObjAllocPost_lock = NULL;
Mutex* OsrList_lock = NULL;
Mutex* ImageFileReaderTable_lock = NULL;
#ifndef PRODUCT
Mutex* FullGCALot_lock = NULL;
#endif
@ -227,6 +229,7 @@ void mutex_init() {
def(ProfilePrint_lock , Mutex , leaf, false, Monitor::_safepoint_check_always); // serial profile printing
def(ExceptionCache_lock , Mutex , leaf, false, Monitor::_safepoint_check_always); // serial profile printing
def(OsrList_lock , Mutex , leaf, true, Monitor::_safepoint_check_never);
def(ImageFileReaderTable_lock , Mutex , nonleaf, false, Monitor::_safepoint_check_always); // synchronize image readers open/close
def(Debug1_lock , Mutex , leaf, true, Monitor::_safepoint_check_never);
#ifndef PRODUCT
def(FullGCALot_lock , Mutex , leaf, false, Monitor::_safepoint_check_always); // a lock to make FullGCALot MT safe

View File

@ -102,6 +102,7 @@ extern Monitor* ProfileVM_lock; // a lock used for profiling th
extern Mutex* ProfilePrint_lock; // a lock used to serialize the printing of profiles
extern Mutex* ExceptionCache_lock; // a lock used to synchronize exception cache updates
extern Mutex* OsrList_lock; // a lock used to serialize access to OSR queues
extern Mutex* ImageFileReaderTable_lock; // a lock used to synchronize image readers open/close
#ifndef PRODUCT
extern Mutex* FullGCALot_lock; // a lock to make FullGCALot MT safe

View File

@ -1237,7 +1237,7 @@ bool os::set_boot_path(char fileSep, char pathSep) {
struct stat st;
// modular image if bootmodules.jimage exists
char* jimage = format_boot_path("%/lib/modules/bootmodules.jimage", home, home_len, fileSep, pathSep);
char* jimage = format_boot_path("%/lib/modules/" BOOT_IMAGE_NAME, home, home_len, fileSep, pathSep);
if (jimage == NULL) return false;
bool has_jimage = (os::stat(jimage, &st) == 0);
if (has_jimage) {

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2015, 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 "utilities/endian.hpp"
#include "utilities/bytes.hpp"
#ifndef bswap_16
extern "C" inline u2 bswap_16(u2 x) {
return ((x & 0xFF) << 8) |
((x >> 8) & 0xFF);
}
#endif
#ifndef bswap_32
extern "C" inline u4 bswap_32(u4 x) {
return ((x & 0xFF) << 24) |
((x & 0xFF00) << 8) |
((x >> 8) & 0xFF00) |
((x >> 24) & 0xFF);
}
#endif
#ifndef bswap_64
extern "C" inline u8 bswap_64(u8 x) {
return (u8)bswap_32((u4)x) << 32 |
(u8)bswap_32((u4)(x >> 32));
}
#endif
u2 NativeEndian::get(u2 x) { return x; }
u4 NativeEndian::get(u4 x) { return x; }
u8 NativeEndian::get(u8 x) { return x; }
s2 NativeEndian::get(s2 x) { return x; }
s4 NativeEndian::get(s4 x) { return x; }
s8 NativeEndian::get(s8 x) { return x; }
void NativeEndian::set(u2& x, u2 y) { x = y; }
void NativeEndian::set(u4& x, u4 y) { x = y; }
void NativeEndian::set(u8& x, u8 y) { x = y; }
void NativeEndian::set(s2& x, s2 y) { x = y; }
void NativeEndian::set(s4& x, s4 y) { x = y; }
void NativeEndian::set(s8& x, s8 y) { x = y; }
NativeEndian NativeEndian::_native;
u2 SwappingEndian::get(u2 x) { return bswap_16(x); }
u4 SwappingEndian::get(u4 x) { return bswap_32(x); }
u8 SwappingEndian::get(u8 x) { return bswap_64(x); }
s2 SwappingEndian::get(s2 x) { return bswap_16(x); }
s4 SwappingEndian::get(s4 x) { return bswap_32(x); }
s8 SwappingEndian::get(s8 x) { return bswap_64(x); }
void SwappingEndian::set(u2& x, u2 y) { x = bswap_16(y); }
void SwappingEndian::set(u4& x, u4 y) { x = bswap_32(y); }
void SwappingEndian::set(u8& x, u8 y) { x = bswap_64(y); }
void SwappingEndian::set(s2& x, s2 y) { x = bswap_16(y); }
void SwappingEndian::set(s4& x, s4 y) { x = bswap_32(y); }
void SwappingEndian::set(s8& x, s8 y) { x = bswap_64(y); }
SwappingEndian SwappingEndian::_swapping;
Endian* Endian::get_handler(bool big_endian) {
// If requesting little endian on a little endian machine or
// big endian on a big endian machine use native handler
if (big_endian == is_big_endian()) {
return NativeEndian::get_native();
} else {
// Use swapping handler.
return SwappingEndian::get_swapping();
}
}
Endian* Endian::get_native_handler() {
return NativeEndian::get_native();
}

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2015, 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.
*
*/
#ifndef SHARE_VM_UTILITIES_ENDIAN_HPP
#define SHARE_VM_UTILITIES_ENDIAN_HPP
#include "utilities/globalDefinitions.hpp"
// Selectable endian handling. Endian handlers are used when accessing values
// that are of unknown (until runtime) endian. The only requirement of the values
// accessed are that they are aligned to proper size boundaries (no misalignment.)
// To select an endian handler, one should call Endian::get_handler(big_endian);
// Where big_endian is true if big endian is required and false otherwise. The
// native endian handler can be fetched with Endian::get_native_handler();
// To retrieve a value using the approprate endian, use one of the overloaded
// calls to get. To set a value, then use one of the overloaded set calls.
// Ex.
// s4 value; // Imported value;
// ...
// Endian* endian = Endian::get_handler(true); // Use big endian
// s4 corrected = endian->get(value);
// endian->set(value, 1);
//
class Endian {
public:
virtual u2 get(u2 x) = 0;
virtual u4 get(u4 x) = 0;
virtual u8 get(u8 x) = 0;
virtual s2 get(s2 x) = 0;
virtual s4 get(s4 x) = 0;
virtual s8 get(s8 x) = 0;
virtual void set(u2& x, u2 y) = 0;
virtual void set(u4& x, u4 y) = 0;
virtual void set(u8& x, u8 y) = 0;
virtual void set(s2& x, s2 y) = 0;
virtual void set(s4& x, s4 y) = 0;
virtual void set(s8& x, s8 y) = 0;
// Quick little endian test.
static bool is_little_endian() { u4 x = 1; return *(u1 *)&x != 0; }
// Quick big endian test.
static bool is_big_endian() { return !is_little_endian(); }
// Select an appropriate endian handler.
static Endian* get_handler(bool big_endian);
// Return the native endian handler.
static Endian* get_native_handler();
};
// Normal endian handling.
class NativeEndian : public Endian {
private:
static NativeEndian _native;
public:
u2 get(u2 x);
u4 get(u4 x);
u8 get(u8 x);
s2 get(s2 x);
s4 get(s4 x);
s8 get(s8 x);
void set(u2& x, u2 y);
void set(u4& x, u4 y);
void set(u8& x, u8 y);
void set(s2& x, s2 y);
void set(s4& x, s4 y);
void set(s8& x, s8 y);
static Endian* get_native() { return &_native; }
};
// Swapping endian handling.
class SwappingEndian : public Endian {
private:
static SwappingEndian _swapping;
public:
u2 get(u2 x);
u4 get(u4 x);
u8 get(u8 x);
s2 get(s2 x);
s4 get(s4 x);
s8 get(s8 x);
void set(u2& x, u2 y);
void set(u4& x, u4 y);
void set(u8& x, u8 y);
void set(s2& x, s2 y);
void set(s4& x, s4 y);
void set(s8& x, s8 y);
static Endian* get_swapping() { return &_swapping; }
};
#endif // SHARE_VM_UTILITIES_ENDIAN_HPP

View File

@ -31,6 +31,7 @@
* java.management
* @build TestPromotionToSurvivor
* SurvivorAlignmentTestMain AlignmentHelper
* @ignore 8129886
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2015, 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.
*/
/*
* Retrieves the array of offsets once with MemoryMapImage enabled once disabled.
* @test ImageAttributeOffsetsTest
* @summary Unit test for JVM_ImageAttributeOffsets() method
* @library /testlibrary /../../test/lib
* @build ImageAttributeOffsetsTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+MemoryMapImage ImageAttributeOffsetsTest
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-MemoryMapImage ImageAttributeOffsetsTest
*/
import java.io.File;
import java.nio.ByteOrder;
import sun.hotspot.WhiteBox;
import static jdk.test.lib.Asserts.*;
public class ImageAttributeOffsetsTest {
public static final WhiteBox wb = WhiteBox.getWhiteBox();
public static void main(String... args) throws Exception {
String javaHome = System.getProperty("java.home");
String imageFile = javaHome + File.separator + "lib" + File.separator
+ "modules" + File.separator + "bootmodules.jimage";
if (!(new File(imageFile)).exists()) {
System.out.printf("Test skipped.");
return;
}
boolean bigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
long id = wb.imageOpenImage(imageFile, bigEndian);
boolean passed = true;
// Get offsets
int[] array = wb.imageAttributeOffsets(id);
assertNotNull(array, "Could not retrieve offsets of array");
wb.imageCloseImage(id);
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 2015, 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 closing image opened multiple time. Test closing mutiple time an image.
* @test ImageCloseTest
* @summary Unit test for JVM_ImageClose() method
* @library /testlibrary /../../test/lib
* @build ImageCloseTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ImageCloseTest
*/
import java.io.File;
import java.nio.ByteOrder;
import sun.hotspot.WhiteBox;
public class ImageCloseTest {
public static final WhiteBox wb = WhiteBox.getWhiteBox();
public static void main(String... args) throws Exception {
String javaHome = System.getProperty("java.home");
String imageFile = javaHome + File.separator + "lib" + File.separator
+ "modules" + File.separator + "bootmodules.jimage";
if (!(new File(imageFile)).exists()) {
System.out.printf("Test skipped.");
return;
}
boolean bigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
long id = 0;
// too many opens
for (int i = 0; i < 100; i++) {
id = wb.imageOpenImage(imageFile, bigEndian);
}
wb.imageCloseImage(id);
// too many closes
id = wb.imageOpenImage(imageFile, bigEndian);
for (int i = 0; i < 100; i++) {
wb.imageCloseImage(id);
}
}
}

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2015, 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 that opening image containing wrong headers fails.
* @test ImageFileHeaderTest
* @library /testlibrary /../../test/lib
* @build ImageFileHeaderTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ImageFileHeaderTest
*/
import java.nio.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import sun.hotspot.WhiteBox;
import static jdk.test.lib.Asserts.*;
public class ImageFileHeaderTest {
public static final int MAGIC = 0xCAFEDADA;
public static final short MAJOR = 0;
public static final short MINOR = 1;
public static final WhiteBox wb = WhiteBox.getWhiteBox();
public static ByteBuffer buf;
public static void main(String... args) throws Exception {
ByteOrder endian = getEndian();
// Try to read a non-existing file
assertFalse(wb.readImageFile("bogus"));
// Incomplete header, only include the correct magic
buf = ByteBuffer.allocate(100);
buf.order(endian);
buf.putInt(MAGIC);
assertFalse(testImageFile("invalidheader.jimage"));
// Build a complete header but reverse the endian
buf = ByteBuffer.allocate(100);
buf.order(endian == ByteOrder.LITTLE_ENDIAN ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
buf.putInt(MAGIC);
buf.putShort(MAJOR);
buf.putShort(MINOR);
assertFalse(testImageFile("wrongendian.jimage"));
// Use the wrong magic
buf = ByteBuffer.allocate(100);
buf.order(endian);
buf.putInt(0xBEEFCACE);
buf.putShort(MAJOR);
buf.putShort(MINOR);
assertFalse(testImageFile("wrongmagic.jimage"));
// Wrong major version (current + 1)
buf = ByteBuffer.allocate(100);
buf.order(endian);
buf.putInt(MAGIC);
buf.putShort((short)(MAJOR + 1));
buf.putShort((short)MINOR);
assertFalse(testImageFile("wrongmajorversion.jimage"));
// Wrong major version (negative)
buf = ByteBuffer.allocate(100);
buf.order(endian);
buf.putInt(MAGIC);
buf.putShort((short) -17);
buf.putShort((short)MINOR);
assertFalse(testImageFile("negativemajorversion.jimage"));
// Wrong minor version (current + 1)
buf = ByteBuffer.allocate(100);
buf.order(endian);
buf.putInt(MAGIC);
buf.putShort((short)MAJOR);
buf.putShort((short)(MINOR + 1));
assertFalse(testImageFile("wrongminorversion.jimage"));
// Wrong minor version (negative)
buf = ByteBuffer.allocate(100);
buf.order(endian);
buf.putInt(MAGIC);
buf.putShort((short)MAJOR);
buf.putShort((short) -17);
assertFalse(testImageFile("negativeminorversion.jimage"));
}
public static boolean testImageFile(String filename) throws Exception {
Files.write(Paths.get(filename), buf.array());
System.out.println("Calling ReadImageFile on " + filename);
return wb.readImageFile(filename);
}
public static ByteOrder getEndian() {
String endian = System.getProperty("sun.cpu.endian");
if (endian.equalsIgnoreCase("little")) {
return ByteOrder.LITTLE_ENDIAN;
} else if (endian.equalsIgnoreCase("big")) {
return ByteOrder.BIG_ENDIAN;
}
throw new RuntimeException("Unexpected sun.cpu.endian value: " + endian);
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2015, 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.
*/
/*
* Find the attributes of existing and invalid classes.
* @test ImageFindAttributesTest
* @summary Unit test for JVM_ImageFindAttributes() method
* @library /testlibrary /../../test/lib
* @build ImageFindAttributesTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ImageFindAttributesTest
*/
import java.io.File;
import java.nio.ByteOrder;
import sun.hotspot.WhiteBox;
import static jdk.test.lib.Asserts.*;
public class ImageFindAttributesTest {
public static final WhiteBox wb = WhiteBox.getWhiteBox();
public static void main(String... args) throws Exception {
String javaHome = System.getProperty("java.home");
String imageFile = javaHome + File.separator + "lib" + File.separator
+ "modules" + File.separator + "bootmodules.jimage";
if (!(new File(imageFile)).exists()) {
System.out.printf("Test skipped.");
return;
}
boolean bigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
long id = wb.imageOpenImage(imageFile, bigEndian);
// class resource
String className = "/java.base/java/lang/String.class";
long[] longArr = wb.imageFindAttributes(id, className.getBytes());
assertNotNull(longArr, "Could not retrieve attributes of class " + className);
// non-existent resource
String neClassName = "/java.base/java/lang/NonExistentClass.class";
longArr = wb.imageFindAttributes(id, neClassName.getBytes());
assertNull(longArr, "Failed. Returned not null for non-existent " + neClassName);
// garbage byte array
byte[] buf = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
longArr = wb.imageFindAttributes(id, buf);
assertNull(longArr, "Found attributes for garbage class");
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright (c) 2015, 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 getting all attributes,
* @test ImageGetAttributesTest
* @summary Unit test for JVM_ImageGetAttributes() method
* @library /testlibrary /../../test/lib
* @build LocationConstants ImageGetAttributesTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ImageGetAttributesTest
*/
import java.io.File;
import java.nio.ByteOrder;
import sun.hotspot.WhiteBox;
import static jdk.test.lib.Asserts.*;
public class ImageGetAttributesTest implements LocationConstants {
public static final WhiteBox wb = WhiteBox.getWhiteBox();
public static void main(String... args) throws Exception {
String javaHome = System.getProperty("java.home");
String imageFile = javaHome + File.separator + "lib" + File.separator
+ "modules" + File.separator + "bootmodules.jimage";
if (!(new File(imageFile)).exists()) {
System.out.printf("Test skipped.");
return;
}
testImageGetAttributes(imageFile);
}
private static void testImageGetAttributes(String imageFile) {
boolean bigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
long id = wb.imageOpenImage(imageFile, bigEndian);
try {
long stringsSize = wb.imageGetStringsSize(id);
assertNE(stringsSize, 0, "strings size is 0");
int[] array = wb.imageAttributeOffsets(id);
assertNotNull(array, "Could not retrieve offsets of array");
// Get non-null attributes
boolean attFound = false;
int[] idx = {-1, -1, -1};
// first non-null attribute
for (int i = 0; i < array.length; i++) {
if (array[i] != 0) {
attFound = true;
idx[0] = i;
break;
}
}
// middle non-null attribute
for (int i = array.length / 2; i < array.length; i++) {
if (array[i] != 0) {
attFound = true;
idx[1] = i;
break;
}
}
// last non-null attribute
for (int i = array.length - 1; i >= 0; i--) {
if (array[i] != 0) {
attFound = true;
idx[2] = i;
break;
}
}
assertTrue(attFound, "Failed. No non-null offset attributes");
// test cases above
for (int i = 0; i < 3; i++) {
if (idx[i] != -1) {
long[] attrs = wb.imageGetAttributes(id, (int) array[idx[i]]);
long module = attrs[LOCATION_ATTRIBUTE_MODULE];
long parent = attrs[LOCATION_ATTRIBUTE_PARENT];
long base = attrs[LOCATION_ATTRIBUTE_BASE];
long ext = attrs[LOCATION_ATTRIBUTE_EXTENSION];
if ((module >= 0) && (module < stringsSize)
&& (parent >= 0) && (parent < stringsSize)
&& (base != 0)
&& (ext >= 0) && (ext < stringsSize)) {
} else {
System.out.printf("Failed. Read attribute offset %d (position %d) but wrong offsets\n",
array[idx[i]], idx[i]);
System.out.printf(" offsets: module = %d parent = %d base = %d extention = %d\n",
module, parent, base, ext);
throw new RuntimeException("Read attribute offset error");
}
} else {
System.out.printf("Failed. Could not read attribute offset %d (position %d)\n",
array[idx[i]], idx[i]);
throw new RuntimeException("Read attribute offset error");
}
}
} finally {
wb.imageCloseImage(id);
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2015, 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 accessing the data address of a jimage. This only makes sense when the
* entire jimage is mapped into memory.
* @test ImageGetDataAddressTest
* @summary Unit test for JVM_ImageGetDataAddress() method
* @library /testlibrary /../../test/lib
* @build ImageGetDataAddressTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+MemoryMapImage ImageGetDataAddressTest +
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-MemoryMapImage ImageGetDataAddressTest -
*/
import java.io.File;
import java.nio.ByteOrder;
import sun.hotspot.WhiteBox;
import static jdk.test.lib.Asserts.*;
public class ImageGetDataAddressTest {
public static final WhiteBox wb = WhiteBox.getWhiteBox();
public static void main(String... args) throws Exception {
String javaHome = System.getProperty("java.home");
String imageFile = javaHome + File.separator + "lib" + File.separator
+ "modules" + File.separator + "bootmodules.jimage";
if (!(new File(imageFile)).exists()) {
System.out.printf("Test skipped.");
return;
}
boolean isMMap = args[0].equals("+");
boolean bigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
long id = wb.imageOpenImage(imageFile, bigEndian);
// get data for valid id
long dataAddr = wb.imageGetDataAddress(id);
assertFalse((dataAddr == 0) && isMMap, "Failed. Data address is " + dataAddr + " for valid id\n");
// get data for invalid id == 0
dataAddr = wb.imageGetDataAddress(0);
assertTrue(dataAddr == 0, "Failed. Data address is " + dataAddr + " for zero id\n");
wb.imageCloseImage(id);
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2015, 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 the address of the jimage index.
* @test ImageGetIndexAddressTest
* @summary Unit test for JVM_ImageGetIndexAddress() method
* @library /testlibrary /../../test/lib
* @build ImageGetIndexAddressTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ImageGetIndexAddressTest
*/
import java.io.File;
import java.nio.ByteOrder;
import sun.hotspot.WhiteBox;
import static jdk.test.lib.Asserts.*;
public class ImageGetIndexAddressTest {
public static final WhiteBox wb = WhiteBox.getWhiteBox();
public static void main(String... args) throws Exception {
String javaHome = System.getProperty("java.home");
String imageFile = javaHome + File.separator + "lib" + File.separator
+ "modules" + File.separator + "bootmodules.jimage";
if (!(new File(imageFile)).exists()) {
System.out.printf("Test skipped.");
return;
}
boolean bigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
long id = wb.imageOpenImage(imageFile, bigEndian);
// get index for valid id
long indexAddr = wb.imageGetIndexAddress(id);
assertFalse(indexAddr == 0, "Failed. Index address is zero for valid id");
// get index for invalid id == 0
indexAddr = wb.imageGetIndexAddress(0);
assertTrue(indexAddr == 0, "Failed. Index address is" + indexAddr + " for zero id\n");
wb.imageCloseImage(id);
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2015, 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 that the string referenced by an attribute is retrieved.
* @test ImageGetStringBytesTest
* @summary Unit test for JVM_ImageGetStringBytes() method
* @library /testlibrary /../../test/lib
* @build LocationConstants ImageGetStringBytesTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ImageGetStringBytesTest
*/
import java.io.File;
import java.nio.ByteOrder;
import sun.hotspot.WhiteBox;
import static jdk.test.lib.Asserts.*;
public class ImageGetStringBytesTest implements LocationConstants {
public static final WhiteBox wb = WhiteBox.getWhiteBox();
public static void main(String... args) throws Exception {
String javaHome = System.getProperty("java.home");
String imageFile = javaHome + File.separator + "lib" + File.separator
+ "modules" + File.separator + "bootmodules.jimage";
if (!(new File(imageFile)).exists()) {
System.out.printf("Test skipped.");
return;
}
boolean bigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
long id = wb.imageOpenImage(imageFile, bigEndian);
String className = "/java.base/java/lang/String.class";
long[] offsetArr = wb.imageFindAttributes(id, className.getBytes());
// Module
assertTrue(checkAttribute(id, offsetArr, LOCATION_ATTRIBUTE_MODULE, "Module"));
// Parent
assertTrue(checkAttribute(id, offsetArr, LOCATION_ATTRIBUTE_PARENT, "Parent"));
// Base
assertTrue(checkAttribute(id, offsetArr, LOCATION_ATTRIBUTE_BASE, "Base"));
// Extension
assertTrue(checkAttribute(id, offsetArr, LOCATION_ATTRIBUTE_EXTENSION, "Extension"));
wb.imageCloseImage(id);
}
private static boolean checkAttribute(long id, long[] offsetArr, int attrId, String attrName) {
long offset = offsetArr[attrId];
return wb.imageGetStringBytes(id, (int) offset) != null;
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2015, 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 image opening/closing
* @test ImageOpenTest
* @summary Unit test for JVM_ImageOpen() method
* @library /testlibrary /../../test/lib
* @build ImageOpenTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ImageOpenTest
*/
import java.io.File;
import java.nio.ByteOrder;
import sun.hotspot.WhiteBox;
import static jdk.test.lib.Asserts.*;
public class ImageOpenTest {
public static final WhiteBox wb = WhiteBox.getWhiteBox();
public static void main(String... args) throws Exception {
String javaHome = System.getProperty("java.home");
String nonexistentImageFile = javaHome + "/lib/modules/nonexistent.jimage";
String bootmodulesImageFile = javaHome + File.separator + "lib" + File.separator
+ "modules" + File.separator + "bootmodules.jimage";
if (!(new File(bootmodulesImageFile)).exists()) {
System.out.printf("Test skipped.");
return;
}
boolean bigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
// open nonexistent image
long id = wb.imageOpenImage(nonexistentImageFile, bigEndian);
assertTrue(id == 0L, "Failed. Get id " + id + "instead of 0 on opening nonexistent file\n");
wb.imageCloseImage(id);
// open bootmodules image
id = wb.imageOpenImage(bootmodulesImageFile, bigEndian);
assertFalse(id == 0, "Failed. Get id 0 on opening bootmodules.jimage");
wb.imageCloseImage(id);
// non-native endian
id = wb.imageOpenImage(bootmodulesImageFile, !bigEndian);
assertFalse(id == 0, "Failed. Get id 0 on opening bootmodules.jimage with non-native endian");
wb.imageCloseImage(id);
//
// open several times
//
id = wb.imageOpenImage(bootmodulesImageFile, bigEndian);
long id1 = wb.imageOpenImage(bootmodulesImageFile, bigEndian);
long id2 = wb.imageOpenImage(bootmodulesImageFile, bigEndian);
assertTrue((id == id1) && (id == id2), "Failed. Open thee times with ids " + id + " " + id1 + " " + id1);
wb.imageCloseImage(id);
wb.imageCloseImage(id1);
wb.imageCloseImage(id2);
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2015, 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 reading resource content.
* @test ImageReadTest
* @summary Unit test for JVM_ImageRead() method
* @library /testlibrary /../../test/lib
* @build LocationConstants ImageReadTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+MemoryMapImage ImageReadTest +
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-MemoryMapImage ImageReadTest -
*/
import java.io.File;
import java.nio.ByteBuffer;
import sun.hotspot.WhiteBox;
import static jdk.test.lib.Asserts.*;
public class ImageReadTest implements LocationConstants {
public static final WhiteBox wb = WhiteBox.getWhiteBox();
public static void main(String... args) throws Exception {
String javaHome = System.getProperty("java.home");
String imageFile = javaHome + File.separator + "lib"
+ File.separator + "modules" + File.separator
+ "bootmodules.jimage";
if (!(new File(imageFile)).exists()) {
System.out.printf("Test skipped.");
return;
}
boolean isMMap = args[0].equals("+");
long id = wb.imageOpenImage(imageFile, isMMap);
final String mm = isMMap ? "-XX:+MemoryMapImage" : "-XX:-MemoryMapImage";
final int magic = 0xCAFEBABE;
String className = "/java.base/java/lang/String.class";
long[] offsetArr = wb.imageFindAttributes(id, className.getBytes());
long offset = offsetArr[LOCATION_ATTRIBUTE_OFFSET];
long size = offsetArr[LOCATION_ATTRIBUTE_UNCOMPRESSED];
// positive: read
ByteBuffer buf = ByteBuffer.allocateDirect((int) size);
assertTrue(wb.imageRead(id, offset, buf, size), "Failed. Read operation returned false, should be true");
int m = buf.getInt();
assertTrue(m == magic, "Failed. Read operation returned true but wrong magic = " + magic);
// positive: mmap
if (isMMap) {
long dataAddr = wb.imageGetDataAddress(id);
assertFalse(dataAddr == 0L, "Failed. Did not obtain data address on mmapped test");
int data = wb.imageGetIntAtAddress(dataAddr, (int) offset, true);
assertTrue(data == magic, "Failed. MMap operation returned true but wrong magic = " + data);
}
// negative: wrong offset
boolean success = wb.imageRead(id, -100, buf, size);
assertFalse(success, "Failed. Read operation (wrong offset): returned true");
// negative: too big offset
long filesize = new File(imageFile).length();
success = wb.imageRead(id, filesize + 1, buf, size);
assertFalse(success, "Failed. Read operation (offset > file size) returned true");
// negative: negative size
success = wb.imageRead(id, offset, buf, -100);
assertFalse(success, "Failed. Read operation (negative size) returned true");
wb.imageCloseImage(id);
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2015, 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.
*/
public interface LocationConstants {
// keep this in sync with enum in ImageLocation C++ class in the
// hotspot's C++ header file imageFile.hpp
public static final int LOCATION_ATTRIBUTE_END = 0; // End of attribute stream marker
public static final int LOCATION_ATTRIBUTE_MODULE = 1; // String table offset of module name
public static final int LOCATION_ATTRIBUTE_PARENT = 2; // String table offset of resource path parent
public static final int LOCATION_ATTRIBUTE_BASE = 3; // String table offset of resource path base
public static final int LOCATION_ATTRIBUTE_EXTENSION = 4; // String table offset of resource path extension
public static final int LOCATION_ATTRIBUTE_OFFSET = 5; // Container byte offset of resource
public static final int LOCATION_ATTRIBUTE_COMPRESSED = 6; // In image byte size of the compressed resource
public static final int LOCATION_ATTRIBUTE_UNCOMPRESSED = 7; // In memory byte size of the uncompressed resource
public static final int LOCATION_ATTRIBUTE_COUNT = 8; // Number of attribute kinds
}