Merge
This commit is contained in:
commit
88ff99b454
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
121
hotspot/src/share/vm/classfile/imageDecompressor.cpp
Normal file
121
hotspot/src/share/vm/classfile/imageDecompressor.cpp
Normal 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
|
137
hotspot/src/share/vm/classfile/imageDecompressor.hpp
Normal file
137
hotspot/src/share/vm/classfile/imageDecompressor.hpp
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
************************************************************************/
|
||||
|
@ -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;",
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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") \
|
||||
\
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
97
hotspot/src/share/vm/utilities/endian.cpp
Normal file
97
hotspot/src/share/vm/utilities/endian.cpp
Normal 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();
|
||||
}
|
119
hotspot/src/share/vm/utilities/endian.hpp
Normal file
119
hotspot/src/share/vm/utilities/endian.hpp
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
68
hotspot/test/runtime/modules/ImageFile/ImageCloseTest.java
Normal file
68
hotspot/test/runtime/modules/ImageFile/ImageCloseTest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
126
hotspot/test/runtime/modules/ImageFile/ImageFileHeaderTest.java
Normal file
126
hotspot/test/runtime/modules/ImageFile/ImageFileHeaderTest.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
84
hotspot/test/runtime/modules/ImageFile/ImageOpenTest.java
Normal file
84
hotspot/test/runtime/modules/ImageFile/ImageOpenTest.java
Normal 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);
|
||||
}
|
||||
}
|
97
hotspot/test/runtime/modules/ImageFile/ImageReadTest.java
Normal file
97
hotspot/test/runtime/modules/ImageFile/ImageReadTest.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user