Merge
authorjfdenise
Thu, 25 Jun 2015 20:47:46 +0000
changeset 31609 a02d832f2880
parent 31607 a584c9066638 (current diff)
parent 31608 b5cb9a07591a (diff)
child 31610 b05ea6f92971
Merge
--- a/hotspot/make/aix/makefiles/mapfile-vers-debug	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/make/aix/makefiles/mapfile-vers-debug	Thu Jun 25 20:47:46 2015 +0000
@@ -141,6 +141,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;
--- a/hotspot/make/aix/makefiles/mapfile-vers-product	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/make/aix/makefiles/mapfile-vers-product	Thu Jun 25 20:47:46 2015 +0000
@@ -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;
--- a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-debug	Thu Jun 25 20:47:46 2015 +0000
@@ -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
--- a/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/make/bsd/makefiles/mapfile-vers-darwin-product	Thu Jun 25 20:47:46 2015 +0000
@@ -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
--- a/hotspot/make/bsd/makefiles/mapfile-vers-debug	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/make/bsd/makefiles/mapfile-vers-debug	Thu Jun 25 20:47:46 2015 +0000
@@ -141,6 +141,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;
--- a/hotspot/make/bsd/makefiles/mapfile-vers-product	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/make/bsd/makefiles/mapfile-vers-product	Thu Jun 25 20:47:46 2015 +0000
@@ -141,6 +141,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;
--- a/hotspot/make/linux/makefiles/mapfile-vers-debug	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/make/linux/makefiles/mapfile-vers-debug	Thu Jun 25 20:47:46 2015 +0000
@@ -141,6 +141,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;
--- a/hotspot/make/linux/makefiles/mapfile-vers-product	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/make/linux/makefiles/mapfile-vers-product	Thu Jun 25 20:47:46 2015 +0000
@@ -141,6 +141,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;
--- a/hotspot/make/solaris/makefiles/mapfile-vers	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/make/solaris/makefiles/mapfile-vers	Thu Jun 25 20:47:46 2015 +0000
@@ -141,6 +141,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;
--- a/hotspot/src/share/vm/classfile/classLoader.cpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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 @@
   _dir = copy;
 }
 
-
 ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
   // construct full path name
   char path[JVM_MAXPATHLEN];
@@ -352,16 +350,25 @@
   }
 }
 
-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 @@
 }
 
 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 (!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) {
 
-  if (buffer) {
+      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 @@
   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 @@
 }
 
 bool ClassPathImageEntry::is_jrt() {
-  return string_ends_with(name(), "bootmodules.jimage");
+  return string_ends_with(name(), BOOT_IMAGE_NAME);
 }
 #endif
 
@@ -557,10 +582,9 @@
         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;
--- a/hotspot/src/share/vm/classfile/classLoader.hpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/classfile/classLoader.hpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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 @@
   }
   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 @@
  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 @@
   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 @@
   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 @@
 };
 
 // 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);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/imageDecompressor.cpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/imageDecompressor.hpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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
--- a/hotspot/src/share/vm/classfile/imageFile.cpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/classfile/imageFile.cpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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"
 
-// Compute the Perfect Hashing hash code for the supplied string.
-u4 ImageStrings::hash_code(const char* string, u4 seed) {
+// 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 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) {
+// 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);
+  _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 @@
     (_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;
   }
+}
 
+// 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;
 }
 
-// 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;
+// 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);
   }
-
-  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;
-}
-
-// 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.
-  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.
-  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.
-  const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);
-  next = ImageStrings::starts_with(next, extension);
-
-  // True only if complete match and no more characters.
-  return next && *next == '\0';
+  return false;
 }
 
-// Return the resource for the supplied location.
-u1* ImageFile::get_resource(ImageLocation& location) 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 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;
+// 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++ = '/';
   }
-
-  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;
+  // Get parent (package) string.
+  const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);
+  // 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);
+  // 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);
+  // 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';
 }
 
-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);
-    }
+// 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 == '\0';
 }
 
-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 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 = location.get_attribute(ImageLocation::ATTRIBUTE_OFFSET);
+  u8 uncompressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
+  u8 compressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_COMPRESSED);
+  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");
   }
-
-  return pkgs;
 }
--- a/hotspot/src/share/vm/classfile/imageFile.hpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/classfile/imageFile.hpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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 @@
 //    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 @@
 //    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 @@
   // 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 @@
   }
 };
 
-// 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;
+//
+// 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); }
+  };
 
-  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.
+  // 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); }
   };
 
-  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
+  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 an image file, reuse structure if file already open.
+  static ImageFileReader* open(const char* name, bool big_endian = Endian::is_big_endian());
 
-  // Open image file for access.
+  // 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 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 location attribute stream for location i.
-  inline u1* get_location_data(u4 i) const {
-    u4 offset = _offsets_table[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 offset != 0 ? _location_bytes + offset : NULL;
+    return get_location_offset_data(offset);
   }
 
-  // Return the attribute stream for a named resourced.
-  u1* find_location_data(const char* path) const;
+  // 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
--- a/hotspot/src/share/vm/precompiled/precompiled.hpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/precompiled/precompiled.hpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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"
--- a/hotspot/src/share/vm/prims/jvm.cpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/prims/jvm.cpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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 @@
   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
--- a/hotspot/src/share/vm/prims/jvm.h	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/prims/jvm.h	Thu Jun 25 20:47:46 2015 +0000
@@ -571,6 +571,52 @@
 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
  ************************************************************************/
--- a/hotspot/src/share/vm/prims/whitebox.cpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/prims/whitebox.cpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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 @@
   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 @@
   {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;",
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Thu Jun 25 20:47:46 2015 +0000
@@ -1582,6 +1582,9 @@
   // 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 @@
   }
 }
 
+  // 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) {
--- a/hotspot/src/share/vm/runtime/arguments.hpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/runtime/arguments.hpp	Thu Jun 25 20:47:46 2015 +0000
@@ -347,6 +347,8 @@
   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();
--- a/hotspot/src/share/vm/runtime/globals.hpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Thu Jun 25 20:47:46 2015 +0000
@@ -1093,6 +1093,9 @@
   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")                    \
                                                                             \
--- a/hotspot/src/share/vm/runtime/init.cpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/runtime/init.cpp	Thu Jun 25 20:47:46 2015 +0000
@@ -82,6 +82,7 @@
 // during VM shutdown
 void perfMemory_exit();
 void ostream_exit();
+bool image_decompressor_init();
 
 void vm_init_globals() {
   check_ThreadShadow();
@@ -115,6 +116,9 @@
   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();
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp	Thu Jun 25 20:47:46 2015 +0000
@@ -100,6 +100,8 @@
 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 @@
   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
--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp	Thu Jun 25 20:47:46 2015 +0000
@@ -102,6 +102,7 @@
 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
--- a/hotspot/src/share/vm/runtime/os.cpp	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/src/share/vm/runtime/os.cpp	Thu Jun 25 20:47:46 2015 +0000
@@ -1237,7 +1237,7 @@
   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) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/utilities/endian.cpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/utilities/endian.hpp	Thu Jun 25 20:47:46 2015 +0000
@@ -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
--- a/hotspot/test/gc/survivorAlignment/TestPromotionToSurvivor.java	Thu Jun 25 18:14:54 2015 +0000
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionToSurvivor.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/ImageAttributeOffsetsTest.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/ImageCloseTest.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/ImageFileHeaderTest.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/ImageFindAttributesTest.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/ImageGetAttributesTest.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/ImageGetDataAddressTest.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/ImageGetIndexAddressTest.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/ImageGetStringBytesTest.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/ImageOpenTest.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/ImageReadTest.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/modules/ImageFile/LocationConstants.java	Thu Jun 25 20:47:46 2015 +0000
@@ -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
+}