8087181: Move native jimage code to its own library (maybe libjimage)
Reviewed-by: alanb, lfoltan, hseigel, acorn
Contributed-by: james.laskey@oracle.com, jean-francois.denise@oracle.com, roger.riggs@oracle.com
--- a/jdk/make/lib/CoreLibraries.gmk Mon Aug 31 21:48:00 2015 +0300
+++ b/jdk/make/lib/CoreLibraries.gmk Fri Sep 04 10:11:43 2015 -0300
@@ -238,6 +238,48 @@
##########################################################################################
+$(eval $(call SetupNativeCompilation,BUILD_LIBJIMAGE, \
+ LIBRARY := jimage, \
+ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+ OPTIMIZATION := LOW, \
+ SRC := $(JDK_TOPDIR)/src/java.base/share/native/libjimage \
+ $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjimage, \
+ EXCLUDES := $(LIBJIMAGE_EXCLUDES), \
+ CFLAGS := $(CFLAGS_JDKLIB) \
+ $(JIMAGELIB_CPPFLAGS) \
+ -I$(JDK_TOPDIR)/src/java.base/share/native/libjava \
+ -I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjava \
+ -I$(JDK_TOPDIR)/src/java.base/share/native/libjimage \
+ -I$(SUPPORT_OUTPUTDIR)/headers/java.base, \
+ CFLAGS_unix := -UDEBUG, \
+ MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libjimage/mapfile-vers, \
+ LDFLAGS := $(LDFLAGS_JDKLIB) \
+ $(call SET_SHARED_LIBRARY_ORIGIN) \
+ $(EXPORT_JIMAGE_FUNCS), \
+ LDFLAGS_windows := -export:JIMAGE_Open -export:JIMAGE_Close \
+ -export:JIMAGE_PackageToModule \
+ -export:JIMAGE_FindResource -export:JIMAGE_GetResource \
+ -export:JIMAGE_ResourceIterator, \
+ LDFLAGS_SUFFIX_unix := -ljvm -ldl $(LIBCXX), \
+ LDFLAGS_SUFFIX_linux := , \
+ LDFLAGS_SUFFIX_solaris := -lc, \
+ LDFLAGS_SUFFIX_aix := ,\
+ LDFLAGS_SUFFIX_macosx := -lc++, \
+ LDFLAGS_SUFFIX_windows := jvm.lib, \
+ VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \
+ RC_FLAGS := $(RC_FLAGS) \
+ -D "JDK_FNAME=jimage.dll" \
+ -D "JDK_INTERNAL_NAME=jimage" \
+ -D "JDK_FTYPE=0x2L", \
+ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjimage, \
+ DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
+
+$(BUILD_LIBJIMAGE): $(BUILD_LIBJAVA)
+
+TARGETS += $(BUILD_LIBJIMAGE)
+
+##########################################################################################
+
LIBJLI_SRC_DIRS := $(call FindSrcDirsForLib, java.base, jli)
LIBJLI_CFLAGS := $(CFLAGS_JDKLIB)
--- a/jdk/make/mapfiles/libjava/mapfile-vers Mon Aug 31 21:48:00 2015 +0300
+++ b/jdk/make/mapfiles/libjava/mapfile-vers Fri Sep 04 10:11:43 2015 -0300
@@ -240,16 +240,6 @@
Java_java_util_TimeZone_getSystemTimeZoneID;
Java_java_util_TimeZone_getSystemGMTOffsetID;
Java_java_util_concurrent_atomic_AtomicLong_VMSupportsCS8;
- Java_jdk_internal_jimage_ImageNativeSubstrate_openImage;
- Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage;
- Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress;
- Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress;
- Java_jdk_internal_jimage_ImageNativeSubstrate_read;
- Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed;
- Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes;
- Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes;
- Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes;
- Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets;
Java_sun_misc_MessageUtils_toStderr;
Java_sun_misc_MessageUtils_toStdout;
Java_sun_misc_NativeSignalHandler_handle0;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/mapfiles/libjimage/mapfile-vers Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,55 @@
+#
+# 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. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# 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.
+#
+
+# Define public interface.
+
+SUNWprivate_1.1 {
+ global:
+ JNI_OnLoad;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_openImage;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_read;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Open;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Close;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1FindResource;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1GetResource;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1PackageToModule;
+ Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Resources;
+ JIMAGE_Open;
+ JIMAGE_Close;
+ JIMAGE_PackageToModule;
+ JIMAGE_FindResource;
+ JIMAGE_GetResource;
+ JIMAGE_ResourceIterator;
+ local:
+ *;
+};
--- a/jdk/make/mapfiles/libzip/reorder-sparc Mon Aug 31 21:48:00 2015 +0300
+++ b/jdk/make/mapfiles/libzip/reorder-sparc Fri Sep 04 10:11:43 2015 -0300
@@ -12,6 +12,7 @@
text: .text%addMetaName: OUTPUTDIR/zip_util.o;
text: .text%ZIP_FindEntry;
text: .text%ZIP_GetEntry;
+text: .text%ZIP_InflateFully;
text: .text%ZIP_Lock;
text: .text%ZIP_Unlock;
text: .text%ZIP_FreeEntry;
--- a/jdk/make/mapfiles/libzip/reorder-sparcv9 Mon Aug 31 21:48:00 2015 +0300
+++ b/jdk/make/mapfiles/libzip/reorder-sparcv9 Fri Sep 04 10:11:43 2015 -0300
@@ -11,6 +11,7 @@
text: .text%addMetaName: OUTPUTDIR/zip_util.o;
text: .text%ZIP_FindEntry;
text: .text%ZIP_GetEntry;
+text: .text%ZIP_InflateFully;
text: .text%ZIP_Lock;
text: .text%ZIP_Unlock;
text: .text%ZIP_FreeEntry;
--- a/jdk/make/mapfiles/libzip/reorder-x86 Mon Aug 31 21:48:00 2015 +0300
+++ b/jdk/make/mapfiles/libzip/reorder-x86 Fri Sep 04 10:11:43 2015 -0300
@@ -12,6 +12,7 @@
text: .text%addMetaName: OUTPUTDIR/zip_util.o;
text: .text%ZIP_FindEntry;
text: .text%ZIP_GetEntry;
+text: .text%ZIP_InflateFully;
text: .text%ZIP_Lock;
text: .text%ZIP_Unlock;
text: .text%ZIP_FreeEntry;
--- a/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java Mon Aug 31 21:48:00 2015 +0300
+++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java Fri Sep 04 10:11:43 2015 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -34,7 +34,7 @@
import java.util.Comparator;
import java.util.stream.IntStream;
-public class BasicImageReader {
+public class BasicImageReader implements AutoCloseable {
private final String imagePath;
private final ImageSubstrate substrate;
private final ByteOrder byteOrder;
--- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java Mon Aug 31 21:48:00 2015 +0300
+++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java Fri Sep 04 10:11:43 2015 -0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -30,7 +30,18 @@
import sun.misc.JavaNioAccess;
import sun.misc.SharedSecrets;
-final class ImageNativeSubstrate implements ImageSubstrate {
+public final class ImageNativeSubstrate implements ImageSubstrate {
+ static {
+ java.security.AccessController.doPrivileged(
+ new java.security.PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ System.loadLibrary("jimage");
+ return null;
+ }
+ });
+ }
+
private static final JavaNioAccess NIOACCESS =
SharedSecrets.getJavaNioAccess();
@@ -52,6 +63,20 @@
native static long[] findAttributes(long id, byte[] path);
native static int[] attributeOffsets(long id);
+ public native static long JIMAGE_Open(String path) throws IOException;
+ public native static void JIMAGE_Close(long jimageHandle);
+ public native static long JIMAGE_FindResource(long jimageHandle,
+ String moduleName, String Version, String path,
+ long[] size);
+ public native static long JIMAGE_GetResource(long jimageHandle,
+ long locationHandle, byte[] buffer, long size);
+ // Get an array of names that match; return the count found upto array size
+ public native static int JIMAGE_Resources(long jimageHandle,
+ String[] outputNames);
+ // Return the module name for the package
+ public native static String JIMAGE_PackageToModule(long imageHandle,
+ String packageName);
+
static ByteBuffer newDirectByteBuffer(long address, long capacity) {
assert capacity < Integer.MAX_VALUE;
return NIOACCESS.newDirectByteBuffer(address, (int)capacity, null);
--- a/jdk/src/java.base/share/native/include/jvm.h Mon Aug 31 21:48:00 2015 +0300
+++ b/jdk/src/java.base/share/native/include/jvm.h Fri Sep 04 10:11:43 2015 -0300
@@ -557,48 +557,6 @@
JVM_SupportsCX8(void);
/*
- * jdk.internal.jimage
- */
-
-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);
-/*
* com.sun.dtrace.jsdt support
*/
--- a/jdk/src/java.base/share/native/libjava/Image.c Mon Aug 31 21:48:00 2015 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,189 +0,0 @@
-/*
- * 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 <string.h>
-
-#include "jni.h"
-#include "jvm.h"
-#include "jdk_internal_jimage_ImageNativeSubstrate.h"
-
-JNIEXPORT jlong JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_openImage(JNIEnv *env,
- jclass cls, jstring path, jboolean big_endian) {
- const char *nativePath;
- jlong ret;
-
- nativePath = (*env)->GetStringUTFChars(env, path, NULL);
- ret = JVM_ImageOpen(env, nativePath, big_endian);
- (*env)->ReleaseStringUTFChars(env, path, nativePath);
- return ret;
-}
-
-JNIEXPORT void JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage(JNIEnv *env,
- jclass cls, jlong id) {
- JVM_ImageClose(env, id);
-}
-
-JNIEXPORT jlong JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress(JNIEnv *env,
- jclass cls, jlong id) {
- return JVM_ImageGetIndexAddress(env, id);
-}
-
-JNIEXPORT jlong JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress(JNIEnv *env,
- jclass cls, jlong id) {
- return JVM_ImageGetDataAddress(env, id);
-}
-
-JNIEXPORT jboolean JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_read(JNIEnv *env,
- jclass cls, jlong id, jlong offset,
- jobject uncompressedBuffer, jlong uncompressed_size) {
- unsigned char* uncompressedAddress;
-
- uncompressedAddress = (unsigned char*) (*env)->GetDirectBufferAddress(env, uncompressedBuffer);
- if (uncompressedBuffer == NULL) {
- return JNI_FALSE;
- }
- return JVM_ImageRead(env, id, offset, uncompressedAddress, uncompressed_size);
-}
-
-JNIEXPORT jboolean JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed(JNIEnv *env,
- jclass cls, jlong id, jlong offset,
- jobject compressedBuffer, jlong compressed_size,
- jobject uncompressedBuffer, jlong uncompressed_size) {
- // Get address of read direct buffer.
- unsigned char* compressedAddress;
- unsigned char* uncompressedAddress;
-
- compressedAddress = (unsigned char*) (*env)->GetDirectBufferAddress(env, compressedBuffer);
- // Get address of decompression direct buffer.
- uncompressedAddress = (unsigned char*) (*env)->GetDirectBufferAddress(env, uncompressedBuffer);
- if (uncompressedBuffer == NULL || compressedBuffer == NULL) {
- return JNI_FALSE;
- }
- return JVM_ImageReadCompressed(env, id, offset, compressedAddress, compressed_size,
- uncompressedAddress, uncompressed_size);
-}
-
-JNIEXPORT jbyteArray JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes(JNIEnv *env,
- jclass cls, jlong id, jint offset) {
- const char* data;
- size_t size;
- jbyteArray byteArray;
- jbyte* rawBytes;
-
- data = JVM_ImageGetStringBytes(env, id, offset);
- // Determine String length.
- size = strlen(data);
- // Allocate byte array.
- byteArray = (*env)->NewByteArray(env, (jsize) size);
- if (byteArray == NULL) {
- return NULL;
- }
- // Get array base address.
- rawBytes = (*env)->GetByteArrayElements(env, byteArray, NULL);
- // Copy bytes from image string table.
- memcpy(rawBytes, data, size);
- // Release byte array base address.
- (*env)->ReleaseByteArrayElements(env, byteArray, rawBytes, 0);
- return byteArray;
-}
-
-JNIEXPORT jlongArray JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes(JNIEnv *env,
- jclass cls, jlong id, jint offset) {
- // Allocate a jlong large enough for all location attributes.
- jlongArray attributes;
- jlong* rawAttributes;
- jlong* ret;
-
- attributes = (*env)->NewLongArray(env, JVM_ImageGetAttributesCount(env));
- if (attributes == NULL) {
- return NULL;
- }
- // Get base address for jlong array.
- rawAttributes = (*env)->GetLongArrayElements(env, attributes, NULL);
- ret = JVM_ImageGetAttributes(env, rawAttributes, id, offset);
- // Release jlong array base address.
- (*env)->ReleaseLongArrayElements(env, attributes, rawAttributes, 0);
- return ret == NULL ? NULL : attributes;
-}
-
-JNIEXPORT jlongArray JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes(JNIEnv *env,
- jclass cls, jlong id, jbyteArray utf8) {
- // Allocate a jlong large enough for all location attributes.
- jsize count;
- jlongArray attributes;
- jlong* rawAttributes;
- jsize size;
- jbyte* rawBytes;
- jlong* ret;
-
- count = JVM_ImageGetAttributesCount(env);
- attributes = (*env)->NewLongArray(env, JVM_ImageGetAttributesCount(env));
- if (attributes == NULL) {
- return NULL;
- }
- // Get base address for jlong array.
- rawAttributes = (*env)->GetLongArrayElements(env, attributes, NULL);
- size = (*env)->GetArrayLength(env, utf8);
- rawBytes = (*env)->GetByteArrayElements(env, utf8, NULL);
- ret = JVM_ImageFindAttributes(env, rawAttributes, rawBytes, size, id);
- (*env)->ReleaseByteArrayElements(env, utf8, rawBytes, 0);
- // Release jlong array base address.
- (*env)->ReleaseLongArrayElements(env, attributes, rawAttributes, 0);
- return ret == NULL ? NULL : attributes;
-
-}
-
-JNIEXPORT jintArray JNICALL
-Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets(JNIEnv *env,
- jclass cls, jlong id) {
- unsigned int length;
- jintArray offsets;
- jint* rawOffsets;
- jint* ret;
-
- length = JVM_ImageAttributeOffsetsLength(env, id);
- offsets = (*env)->NewIntArray(env, length);
- if (offsets == NULL) {
- return NULL;
- }
- // Get base address of result.
- rawOffsets = (*env)->GetIntArrayElements(env, offsets, NULL);
- ret = JVM_ImageAttributeOffsets(env, rawOffsets, length, id);
- if (length == 0) {
- return NULL;
- }
- // Release result base address.
- (*env)->ReleaseIntArrayElements(env, offsets, rawOffsets, 0);
- return ret == NULL ? NULL : offsets;
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,598 @@
+/*
+ * 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 <string.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jdk_util.h"
+#include "endian.hpp"
+#include "imageDecompressor.hpp"
+#include "imageFile.hpp"
+#include "inttypes.hpp"
+#include "jimage.hpp"
+#include "osSupport.hpp"
+
+#include "jdk_internal_jimage_ImageNativeSubstrate.h"
+
+extern bool MemoryMapImage;
+
+// jdk.internal.jimage /////////////////////////////////////////////////////////
+
+// Java entry to open an image file for sharing.
+
+static jlong JIMAGE_Open(JNIEnv *env, const char *nativePath, jboolean big_endian) {
+ // Open image file for reading.
+ ImageFileReader* reader = ImageFileReader::open(nativePath, big_endian != JNI_FALSE);
+ // Return image ID as a jlong.
+ return ImageFileReader::readerToID(reader);
+}
+
+// Java entry for closing a shared image file.
+
+static void JIMAGE_Close(JNIEnv *env, jlong id) {
+ // Convert image ID to image reader structure.
+ ImageFileReader* reader = ImageFileReader::idToReader(id);
+ // If valid reader the close.
+ if (reader != NULL) {
+ ImageFileReader::close(reader);
+ }
+}
+
+// Java entry for accessing the base address of the image index.
+
+static jlong JIMAGE_GetIndexAddress(JNIEnv *env, jlong id) {
+ // 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;
+}
+
+// Java entry for accessing the base address of the image data.
+
+static jlong JIMAGE_GetDataAddress(JNIEnv *env, jlong id) {
+ // 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;
+}
+
+// Java entry for reading an uncompressed resource from the image.
+
+static jboolean JIMAGE_Read(JNIEnv *env, jlong id, jlong offset,
+ unsigned char* uncompressedAddress, jlong uncompressed_size) {
+ // 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);
+}
+
+// Java entry for reading a compressed resource from the image.
+
+static jboolean JIMAGE_ReadCompressed(JNIEnv *env,
+ jlong id, jlong offset,
+ unsigned char* compressedAddress, jlong compressed_size,
+ unsigned char* uncompressedAddress, jlong uncompressed_size) {
+ // 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,
+ (u4) uncompressed_size, &strings);
+ }
+ return (jboolean) is_read;
+}
+
+// Java entry for retrieving UTF-8 bytes from image string table.
+
+static const char* JIMAGE_GetStringBytes(JNIEnv *env, jlong id, jint offset) {
+ // 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;
+}
+
+// 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.
+
+static jlong* JIMAGE_GetAttributes(JNIEnv *env, jlong* rawAttributes, jlong id, jint offset) {
+ // 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;
+}
+
+// Java entry for retrieving location attributes count for attribute offset.
+
+static jsize JIMAGE_GetAttributesCount(JNIEnv *env) {
+ return ImageLocation::ATTRIBUTE_COUNT;
+}
+
+// Java entry for retrieving location attributes for named resource.
+
+static jlong* JIMAGE_FindAttributes(JNIEnv *env, jlong* rawAttributes, jbyte* rawBytes, jsize size, jlong id) {
+ // 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 char[size + 1];
+ memcpy(path, rawBytes, size);
+ path[size] = '\0';
+ // Locate resource location data.
+ ImageLocation location;
+ bool found = reader->find_location(path, location);
+ delete path;
+ // Resource not found.
+ if (!found) return NULL;
+ // Expand stream into array.
+ image_expand_location(env, rawAttributes, location);
+ return rawAttributes;
+}
+
+// Java entry for retrieving all the attribute stream offsets from an image.
+
+static jint* JIMAGE_AttributeOffsets(JNIEnv *env, jint* rawOffsets, unsigned int length, jlong id) {
+ // 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;
+}
+
+// Java entry for retrieving all the attribute stream offsets length from an image.
+
+static unsigned int JIMAGE_AttributeOffsetsLength(JNIEnv *env, jlong id) {
+ // 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;
+}
+
+JNIEXPORT jint JNICALL
+JNI_OnLoad(JavaVM *vm, void *reserved) {
+ JNIEnv *env;
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_2) != JNI_OK) {
+ return JNI_EVERSION; /* JNI version not supported */
+ }
+
+ return JNI_VERSION_1_2;
+}
+
+JNIEXPORT jlong JNICALL
+Java_jdk_internal_jimage_ImageNativeSubstrate_openImage(JNIEnv *env,
+ jclass cls, jstring path, jboolean big_endian) {
+ const char *nativePath;
+ jlong ret;
+
+ nativePath = env->GetStringUTFChars(path, NULL);
+ ret = JIMAGE_Open(env, nativePath, big_endian);
+ env->ReleaseStringUTFChars(path, nativePath);
+ return ret;
+}
+
+JNIEXPORT void JNICALL
+Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage(JNIEnv *env,
+ jclass cls, jlong id) {
+ JIMAGE_Close(env, id);
+}
+
+JNIEXPORT jlong JNICALL
+Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress(JNIEnv *env,
+ jclass cls, jlong id) {
+ return JIMAGE_GetIndexAddress(env, id);
+}
+
+JNIEXPORT jlong JNICALL
+Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress(JNIEnv *env,
+ jclass cls, jlong id) {
+ return JIMAGE_GetDataAddress(env, id);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_jdk_internal_jimage_ImageNativeSubstrate_read(JNIEnv *env,
+ jclass cls, jlong id, jlong offset,
+ jobject uncompressedBuffer, jlong uncompressed_size) {
+ unsigned char* uncompressedAddress;
+
+ uncompressedAddress = (unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer);
+ if (uncompressedAddress == NULL) {
+ return JNI_FALSE;
+ }
+ return JIMAGE_Read(env, id, offset, uncompressedAddress, uncompressed_size);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed(JNIEnv *env,
+ jclass cls, jlong id, jlong offset,
+ jobject compressedBuffer, jlong compressed_size,
+ jobject uncompressedBuffer, jlong uncompressed_size) {
+ // Get address of read direct buffer.
+ unsigned char* compressedAddress;
+ unsigned char* uncompressedAddress;
+
+ compressedAddress = (unsigned char*) env->GetDirectBufferAddress(compressedBuffer);
+ // Get address of decompression direct buffer.
+ uncompressedAddress = (unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer);
+ if (compressedAddress == NULL || uncompressedAddress == NULL) {
+ return JNI_FALSE;
+ }
+ return JIMAGE_ReadCompressed(env, id, offset, compressedAddress, compressed_size,
+ uncompressedAddress, uncompressed_size);
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes(JNIEnv *env,
+ jclass cls, jlong id, jint offset) {
+ const char* data;
+ size_t size;
+ jbyteArray byteArray;
+ jbyte* rawBytes;
+
+ data = JIMAGE_GetStringBytes(env, id, offset);
+ // Determine String length.
+ size = strlen(data);
+ // Allocate byte array.
+ byteArray = env->NewByteArray((jsize) size);
+ if (byteArray == NULL) {
+ return NULL;
+ }
+ // Get array base address.
+ 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;
+}
+
+JNIEXPORT jlongArray JNICALL
+Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes(JNIEnv *env,
+ jclass cls, jlong id, jint offset) {
+ // Allocate a jlong large enough for all location attributes.
+ jlongArray attributes;
+ jlong* rawAttributes;
+ jlong* ret;
+
+ attributes = env->NewLongArray(JIMAGE_GetAttributesCount(env));
+ if (attributes == NULL) {
+ return NULL;
+ }
+ // Get base address for jlong array.
+ rawAttributes = env->GetLongArrayElements(attributes, NULL);
+ ret = JIMAGE_GetAttributes(env, rawAttributes, id, offset);
+ // Release jlong array base address.
+ env->ReleaseLongArrayElements(attributes, rawAttributes, 0);
+ return ret == NULL ? NULL : attributes;
+}
+
+JNIEXPORT jlongArray JNICALL
+Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes(JNIEnv *env,
+ jclass cls, jlong id, jbyteArray utf8) {
+ // Allocate a jlong large enough for all location attributes.
+ jsize count;
+ jlongArray attributes;
+ jlong* rawAttributes;
+ jsize size;
+ jbyte* rawBytes;
+ jlong* ret;
+
+ count = JIMAGE_GetAttributesCount(env);
+ attributes = env->NewLongArray(JIMAGE_GetAttributesCount(env));
+ if (attributes == NULL) {
+ return NULL;
+ }
+ // Get base address for jlong array.
+ rawAttributes = env->GetLongArrayElements(attributes, NULL);
+ size = env->GetArrayLength(utf8);
+ rawBytes = env->GetByteArrayElements(utf8, NULL);
+ ret = JIMAGE_FindAttributes(env, rawAttributes, rawBytes, size, id);
+ env->ReleaseByteArrayElements(utf8, rawBytes, 0);
+ // Release jlong array base address.
+ env->ReleaseLongArrayElements(attributes, rawAttributes, 0);
+ return ret == NULL ? NULL : attributes;
+
+}
+
+JNIEXPORT jintArray JNICALL
+Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets(JNIEnv *env,
+ jclass cls, jlong id) {
+ unsigned int length;
+ jintArray offsets;
+ jint* rawOffsets;
+ jint* ret;
+
+ length = JIMAGE_AttributeOffsetsLength(env, id);
+ offsets = env->NewIntArray(length);
+ if (offsets == NULL) {
+ return NULL;
+ }
+ // Get base address of result.
+ rawOffsets = env->GetIntArrayElements(offsets, NULL);
+ ret = JIMAGE_AttributeOffsets(env, rawOffsets, length, id);
+ if (length == 0) {
+ return NULL;
+ }
+ // Release result base address.
+ env->ReleaseIntArrayElements(offsets, rawOffsets, 0);
+ return ret == NULL ? NULL : offsets;
+}
+
+/*
+ * Class: jdk_internal_jimage_ImageNativeSubstrate
+ * Method: JIMAGE_open
+ * Signature: (Ljava/lang/String;)J
+ */
+JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Open
+(JNIEnv *env, jclass, jstring path) {
+ const char *nativePath = env->GetStringUTFChars(path, NULL);
+ if (nativePath == NULL)
+ return 0; // Exception already thrown
+ jint error;
+ jlong ret = (jlong) JIMAGE_Open(nativePath, &error);
+ env->ReleaseStringUTFChars(path, nativePath);
+ return ret;
+}
+
+/*
+ * Class: jdk_internal_jimage_ImageNativeSubstrate
+ * Method: JIMAGE_Close
+ * Signature: (J)J
+ */
+JNIEXPORT void JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Close
+(JNIEnv *env, jclass, jlong jimageHandle) {
+ JIMAGE_Close((JImageFile*) jimageHandle);
+}
+
+/*
+ * Class: jdk_internal_jimage_ImageNativeSubstrate
+ * Method: JIMAGE_FindResource
+ * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[J)J
+ */
+JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1FindResource
+(JNIEnv *env, jclass, jlong jimageHandle, jstring moduleName,
+ jstring version, jstring path, jlongArray output_size) {
+ const char *native_module = NULL;
+ const char *native_version = NULL;
+ const char *native_path = NULL;
+ jlong * native_array = NULL;
+ jlong size = 0;
+ jlong ret = 0;
+
+ do {
+ native_module = env->GetStringUTFChars(moduleName, NULL);
+ if (native_module == NULL)
+ break;
+ native_version = env->GetStringUTFChars(version, NULL);
+ if (native_version == NULL)
+ break;
+ native_path = env->GetStringUTFChars(path, NULL);
+ if (native_path == NULL)
+ break;
+ if (env->GetArrayLength(output_size) < 1)
+ break;
+ // Get base address for jlong array.
+ native_array = env->GetLongArrayElements(output_size, NULL);
+ if (native_array == NULL)
+ break;
+
+ ret = (jlong) JIMAGE_FindResource((JImageFile *) jimageHandle,
+ native_module, native_version, native_path, &size);
+ if (ret != 0)
+ *native_array = size;
+ } while (0);
+
+ if (native_array != NULL)
+ env->ReleaseLongArrayElements(output_size, native_array, 0);
+ if (native_path != NULL)
+ env->ReleaseStringUTFChars(path, native_path);
+ if (native_version != NULL)
+ env->ReleaseStringUTFChars(path, native_version);
+ if (native_module != NULL)
+ env->ReleaseStringUTFChars(path, native_module);
+
+ return ret;
+}
+
+/*
+ * Class: jdk_internal_jimage_ImageNativeSubstrate
+ * Method: JIMAGE_GetResource
+ * Signature: (JJ[BJ)J
+ */
+JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1GetResource
+(JNIEnv *env, jclass, jlong jimageHandle, jlong jlocationHandle, jbyteArray buffer, jlong size) {
+ jbyte * native_buffer = NULL;
+ jlong actual_size = 0;
+ do {
+ if (env->GetArrayLength(buffer) < size)
+ break;
+
+ native_buffer = env->GetByteArrayElements(buffer, NULL);
+ if (native_buffer == NULL)
+ break;
+
+ actual_size = JIMAGE_GetResource((JImageFile*) jimageHandle,
+ (JImageLocationRef) jlocationHandle,
+ (char *) native_buffer, size);
+ } while (0);
+ // Release byte array
+ if (native_buffer != NULL)
+ env->ReleaseByteArrayElements(buffer, native_buffer, 0);
+
+ return actual_size;
+}
+
+// Structure passed from iterator to a visitor to accumulate the results
+
+struct VisitorData {
+ JNIEnv *env;
+ int size; // current number of strings
+ int max; // Maximum number of strings
+ jobjectArray array; // String array to store the strings
+};
+
+// Visitor to accumulate fully qualified resource names
+
+static bool resourceVisitor(JImageFile* image,
+ const char* module, const char* version, const char* package,
+ const char* name, const char* extension, void* arg) {
+ struct VisitorData *vdata = (struct VisitorData *) arg;
+ JNIEnv* env = vdata->env;
+ if (vdata->size < vdata->max) {
+ // Store if there is room in the array
+ // Concatenate to get full path
+ char fullpath[IMAGE_MAX_PATH];
+ fullpath[0] = '\0';
+ if (*module != '\0') {
+ strncpy(fullpath, "/", IMAGE_MAX_PATH - 1);
+ strncat(fullpath, module, IMAGE_MAX_PATH - 1);
+ strncat(fullpath, "/", IMAGE_MAX_PATH - 1);
+ }
+ if (*package != '\0') {
+ strncat(fullpath, package, IMAGE_MAX_PATH - 1);
+ strncat(fullpath, "/", IMAGE_MAX_PATH - 1);
+ }
+ strncat(fullpath, name, IMAGE_MAX_PATH - 1);
+ if (*extension != '\0') {
+ strncat(fullpath, ".", IMAGE_MAX_PATH - 1);
+ strncat(fullpath, extension, IMAGE_MAX_PATH - 1);
+ }
+ jobject str = env->NewStringUTF(fullpath);
+ JNU_CHECK_EXCEPTION_RETURN(env, true);
+ env->SetObjectArrayElement(vdata->array, vdata->size, str);
+ JNU_CHECK_EXCEPTION_RETURN(env, true);
+ }
+ vdata->size++; // always count so the total size is returned
+ return true;
+}
+
+/*
+ * Class: jdk_internal_jimage_ImageNativeSubstrate
+ * Method: JIMAGE_Resources
+ * Signature: (J)V
+ */
+JNIEXPORT jint JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Resources
+(JNIEnv *env, jclass, jlong jimageHandle,
+ jobjectArray outputNames) {
+ struct VisitorData vdata;
+ vdata.env = env;
+ vdata.max = 0;
+ vdata.size = 0;
+ vdata.array = outputNames;
+
+ vdata.max = (outputNames != NULL) ? env->GetArrayLength(outputNames) : 0;
+ JIMAGE_ResourceIterator((JImageFile*) jimageHandle, &resourceVisitor, &vdata);
+ return vdata.size;
+}
+
+/*
+ * Class: jdk_internal_jimage_ImageNativeSubstrate
+ * Method: JIMAGE_PackageToModule
+ * Signature: (JLjava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1PackageToModule
+(JNIEnv *env, jclass, jlong jimageHandle, jstring package_name) {
+ const char *native_package = NULL;
+ const char *native_module = NULL;
+ jstring module = NULL;
+
+ native_package = env->GetStringUTFChars(package_name, NULL);
+ JNU_CHECK_EXCEPTION_RETURN(env, NULL);
+
+ native_module = JIMAGE_PackageToModule((JImageFile*) jimageHandle, native_package);
+ if (native_module != NULL) {
+ module = env->NewStringUTF(native_module);
+ }
+ env->ReleaseStringUTFChars(package_name, native_package);
+ return module;
+}
+
+JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) {
+ ImageDecompressor::image_decompressor_close();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/endian.cpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,102 @@
+/*
+ * 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 "endian.hpp"
+#include "inttypes.hpp"
+
+// Most modern compilers optimize the bswap routines to native instructions.
+inline static u2 bswap_16(u2 x) {
+ return ((x & 0xFF) << 8) |
+ ((x >> 8) & 0xFF);
+}
+
+inline static u4 bswap_32(u4 x) {
+ return ((x & 0xFF) << 24) |
+ ((x & 0xFF00) << 8) |
+ ((x >> 8) & 0xFF00) |
+ ((x >> 24) & 0xFF);
+}
+
+inline static u8 bswap_64(u8 x) {
+ return (u8)bswap_32((u4)x) << 32 |
+ (u8)bswap_32((u4)(x >> 32));
+}
+
+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();
+ }
+}
+
+// Return a platform u2 from an array in which Big Endian is applied.
+u2 Endian::get_java(u1* x) {
+ return (u2) (x[0]<<8 | x[1]);
+}
+
+// Add a platform u2 to the array as a Big Endian u2
+void Endian::set_java(u1* p, u2 x) {
+ p[0] = (x >> 8) & 0xff;
+ p[1] = x & 0xff;
+}
+
+Endian* Endian::get_native_handler() {
+ return NativeEndian::get_native();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/endian.hpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,124 @@
+/*
+ * 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 LIBJIMAGE_ENDIAN_HPP
+#define LIBJIMAGE_ENDIAN_HPP
+
+#include "inttypes.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();
+
+ // get platform u2 from Java Big endian
+ static u2 get_java(u1* x);
+ // set platform u2 to Java Big endian
+ static void set_java(u1* p, u2 x);
+};
+
+// 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 // LIBJIMAGE_ENDIAN_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,332 @@
+/*
+ * 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 "jni.h"
+#include "imageDecompressor.hpp"
+#include "endian.hpp"
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+typedef jboolean (JNICALL *ZipInflateFully_t)(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg);
+static ZipInflateFully_t ZipInflateFully = NULL;
+
+#ifndef WIN32
+ #define JNI_LIB_PREFIX "lib"
+ #ifdef __APPLE__
+ #define JNI_LIB_SUFFIX ".dylib"
+ #else
+ #define JNI_LIB_SUFFIX ".so"
+ #endif
+#endif
+
+/**
+ * Return the address of the entry point named in the zip shared library.
+ * @param name - the name of the entry point
+ * @return the address of the entry point or NULL
+ */
+static void* findEntry(const char* name) {
+ void *addr = NULL;
+#ifdef WIN32
+ HMODULE handle = GetModuleHandle("zip.dll");
+ if (handle == NULL) {
+ return NULL;
+ }
+ addr = (void*) GetProcAddress(handle, name);
+ return addr;
+#else
+ addr = dlopen(JNI_LIB_PREFIX "zip" JNI_LIB_SUFFIX, RTLD_GLOBAL|RTLD_LAZY);
+ if (addr == NULL) {
+ return NULL;
+ }
+ addr = dlsym(addr, name);
+ return addr;
+#endif
+}
+
+/*
+ * Initialize the array of decompressors.
+ */
+int ImageDecompressor::_decompressors_num = 0;
+ImageDecompressor** ImageDecompressor::_decompressors = NULL;
+void ImageDecompressor::image_decompressor_init() {
+ if (_decompressors == NULL) {
+ ZipInflateFully = (ZipInflateFully_t) findEntry("ZIP_InflateFully");
+ assert(ZipInflateFully != NULL && "ZIP decompressor not found.");
+ _decompressors_num = 2;
+ _decompressors = new ImageDecompressor*[_decompressors_num];
+ _decompressors[0] = new ZipDecompressor("zip");
+ _decompressors[1] = new SharedStringDecompressor("compact-cp");
+ }
+}
+
+void ImageDecompressor::image_decompressor_close() {
+ delete _decompressors;
+}
+
+/*
+ * Locate decompressor.
+ */
+ImageDecompressor* ImageDecompressor::get_decompressor(const char * decompressor_name) {
+ image_decompressor_init();
+ for (int i = 0; i < _decompressors_num; i++) {
+ ImageDecompressor* decompressor = _decompressors[i];
+ assert(decompressor != NULL && "Decompressors not initialized.");
+ if (strcmp(decompressor->get_name(), decompressor_name) == 0) {
+ return decompressor;
+ }
+ }
+ assert(false && "No decompressor found.");
+ return NULL;
+}
+
+/*
+ * Decompression entry point. Called from ImageFileReader::get_resource.
+ */
+void ImageDecompressor::decompress_resource(u1* compressed, u1* uncompressed,
+ u4 uncompressed_size, const ImageStrings* strings) {
+ 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
+ decompressed_resource = new u1[_header._uncompressed_size];
+ // Retrieve the decompressor name
+ const char* decompressor_name = strings->get(_header._decompressor_name_offset);
+ assert(decompressor_name && "image decompressor not found");
+ // Retrieve the decompressor instance
+ ImageDecompressor* decompressor = get_decompressor(decompressor_name);
+ assert(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) {
+ delete compressed_resource_base;
+ }
+ compressed_resource = decompressed_resource;
+ }
+ } while (has_header);
+ memcpy(uncompressed, decompressed_resource, uncompressed_size);
+ delete decompressed_resource;
+}
+
+// Zip decompressor
+
+void ZipDecompressor::decompress_resource(u1* data, u1* uncompressed,
+ ResourceHeader* header, const ImageStrings* strings) {
+ char* msg = NULL;
+ jboolean res = ZipDecompressor::decompress(data, header->_size, uncompressed,
+ header->_uncompressed_size, &msg);
+ assert(res && "decompression failed");
+}
+
+jboolean ZipDecompressor::decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg) {
+ return (*ZipInflateFully)(in, inSize, out, outSize, pmsg);
+}
+
+// END Zip Decompressor
+
+// Shared String decompressor
+
+// array index is the constant pool tag. value is size.
+// eg: array[5] = 8; means size of long is 8 bytes.
+const u1 SharedStringDecompressor::sizes[] = {0, 0, 0, 4, 4, 8, 8, 2, 2, 4, 4, 4, 4, 0, 0, 3, 2, 0, 4};
+/**
+ * Recreate the class by reconstructing the constant pool.
+ */
+void SharedStringDecompressor::decompress_resource(u1* data,
+ u1* uncompressed_resource,
+ ResourceHeader* header, const ImageStrings* strings) {
+ u1* uncompressed_base = uncompressed_resource;
+ u1* data_base = data;
+ int header_size = 8; // magic + major + minor
+ memcpy(uncompressed_resource, data, header_size + 2); //+ cp count
+ uncompressed_resource += header_size + 2;
+ data += header_size;
+ u2 cp_count = Endian::get_java(data);
+ data += 2;
+ for (int i = 1; i < cp_count; i++) {
+ u1 tag = *data;
+ data += 1;
+ switch (tag) {
+
+ case externalized_string:
+ { // String in Strings table
+ *uncompressed_resource = 1;
+ uncompressed_resource += 1;
+ int i = decompress_int(data);
+ const char * string = strings->get(i);
+ int str_length = (int) strlen(string);
+ Endian::set_java(uncompressed_resource, str_length);
+ uncompressed_resource += 2;
+ memcpy(uncompressed_resource, string, str_length);
+ uncompressed_resource += str_length;
+ break;
+ }
+ // Descriptor String has been split and types added to Strings table
+ case externalized_string_descriptor:
+ {
+ *uncompressed_resource = 1;
+ uncompressed_resource += 1;
+ int descriptor_index = decompress_int(data);
+ int indexes_length = decompress_int(data);
+ u1* length_address = uncompressed_resource;
+ uncompressed_resource += 2;
+ int desc_length = 0;
+ const char * desc_string = strings->get(descriptor_index);
+ if (indexes_length > 0) {
+ u1* indexes_base = data;
+ data += indexes_length;
+ char c = *desc_string;
+ do {
+ *uncompressed_resource = c;
+ uncompressed_resource++;
+ desc_length += 1;
+ /*
+ * Every L character is the marker we are looking at in order
+ * to reconstruct the descriptor. Each time an L is found, then
+ * we retrieve the couple token/token at the current index and
+ * add it to the descriptor.
+ * "(L;I)V" and "java/lang","String" couple of tokens,
+ * this becomes "(Ljava/lang/String;I)V"
+ */
+ if (c == 'L') {
+ int index = decompress_int(indexes_base);
+ const char * pkg = strings->get(index);
+ int str_length = (int) strlen(pkg);
+ // the case where we have a package.
+ // reconstruct the type full name
+ if (str_length > 0) {
+ int len = str_length + 1;
+ char* fullpkg = new char[len];
+ char* pkg_base = fullpkg;
+ memcpy(fullpkg, pkg, str_length);
+ fullpkg += str_length;
+ *fullpkg = '/';
+ memcpy(uncompressed_resource, pkg_base, len);
+ uncompressed_resource += len;
+ delete pkg_base;
+ desc_length += len;
+ } else { // Empty package
+ // Nothing to do.
+ }
+ int classIndex = decompress_int(indexes_base);
+ const char * clazz = strings->get(classIndex);
+ int clazz_length = (int) strlen(clazz);
+ memcpy(uncompressed_resource, clazz, clazz_length);
+ uncompressed_resource += clazz_length;
+ desc_length += clazz_length;
+ }
+ desc_string += 1;
+ c = *desc_string;
+ } while (c != '\0');
+ } else {
+ desc_length = (int) strlen(desc_string);
+ memcpy(uncompressed_resource, desc_string, desc_length);
+ uncompressed_resource += desc_length;
+ }
+ Endian::set_java(length_address, desc_length);
+ break;
+ }
+
+ case constant_utf8:
+ { // UTF-8
+ *uncompressed_resource = tag;
+ uncompressed_resource += 1;
+ u2 str_length = Endian::get_java(data);
+ int len = str_length + 2;
+ memcpy(uncompressed_resource, data, len);
+ uncompressed_resource += len;
+ data += len;
+ break;
+ }
+
+ case constant_long:
+ case constant_double:
+ {
+ i++;
+ }
+ default:
+ {
+ *uncompressed_resource = tag;
+ uncompressed_resource += 1;
+ int size = sizes[tag];
+ memcpy(uncompressed_resource, data, size);
+ uncompressed_resource += size;
+ data += size;
+ }
+ }
+ }
+ u4 remain = header->_size - (int)(data - data_base);
+ u4 computed = (u4)(uncompressed_resource - uncompressed_base) + remain;
+ if (header->_uncompressed_size != computed)
+ printf("Failure, expecting %d but getting %d\n", header->_uncompressed_size,
+ computed);
+ assert(header->_uncompressed_size == computed &&
+ "Constant Pool reconstruction failed");
+ memcpy(uncompressed_resource, data, remain);
+}
+
+/*
+ * Decompress integers. Compressed integers are negative.
+ * If positive, the integer is not decompressed.
+ * If negative, length extracted from the first byte, then reconstruct the integer
+ * from the following bytes.
+ * Example of compression: 1 is compressed on 1 byte: 10100001
+ */
+int SharedStringDecompressor::decompress_int(unsigned char*& value) {
+ int len = 4;
+ int res = 0;
+ char b1 = *value;
+ if (is_compressed((signed char)b1)) { // compressed
+ len = get_compressed_length(b1);
+ char clearedValue = b1 &= 0x1F;
+ if (len == 1) {
+ res = clearedValue;
+ } else {
+ res = (clearedValue & 0xFF) << 8 * (len - 1);
+ for (int i = 1; i < len; i++) {
+ res |= (value[i]&0xFF) << 8 * (len - i - 1);
+ }
+ }
+ } else {
+ res = (value[0] & 0xFF) << 24 | (value[1]&0xFF) << 16 |
+ (value[2]&0xFF) << 8 | (value[3]&0xFF);
+ }
+ value += len;
+ return res;
+}
+// END Shared String decompressor
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/imageDecompressor.hpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,162 @@
+/*
+ * 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 LIBJIMAGE_IMAGEDECOMPRESSOR_HPP
+#define LIBJIMAGE_IMAGEDECOMPRESSOR_HPP
+
+#include <assert.h>
+#include <string.h>
+
+#include "imageFile.hpp"
+#include "inttypes.hpp"
+#include "jni.h"
+
+/*
+ * 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 {
+
+private:
+ const char* _name;
+
+ /*
+ * Array of concrete decompressors. This array is used to retrieve the decompressor
+ * that can handle resource decompression.
+ */
+ static ImageDecompressor** _decompressors;
+ /**
+ * Num of decompressors
+ */
+ static int _decompressors_num;
+ /*
+ * Identifier of a decompressor. This name is the identification key to retrieve
+ * decompressor from a resource header.
+ */
+ inline const char* get_name() const { return _name; }
+
+
+protected:
+ ImageDecompressor(const char* name) : _name(name) {
+ }
+ virtual void decompress_resource(u1* data, u1* uncompressed,
+ ResourceHeader* header, const ImageStrings* strings) = 0;
+
+public:
+ static void image_decompressor_init();
+ static void image_decompressor_close();
+ static ImageDecompressor* get_decompressor(const char * decompressor_name) ;
+ static void decompress_resource(u1* compressed, u1* uncompressed,
+ u4 uncompressed_size, const ImageStrings* strings);
+};
+
+/**
+ * Zip decompressor.
+ */
+class ZipDecompressor : public ImageDecompressor {
+public:
+ ZipDecompressor(const char* sym) : ImageDecompressor(sym) { }
+ void decompress_resource(u1* data, u1* uncompressed, ResourceHeader* header,
+ const ImageStrings* strings);
+ static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg);
+};
+
+/*
+ * Shared Strings decompressor. This decompressor reconstruct the class
+ * constant pool UTF_U entries by retrieving strings stored in jimage strings table.
+ * In addition, if the UTF_8 entry is a descriptor, the descriptor has to be rebuilt,
+ * all java type having been removed from the descriptor and added to the sting table.
+ * eg: "(Ljava/lang/String;I)V" ==> "(L;I)V" and "java/lang", "String"
+ * stored in string table. offsets to the 2 strings are compressed and stored in the
+ * constantpool entry.
+ */
+class SharedStringDecompressor : public ImageDecompressor {
+private:
+ // the constant pool tag for UTF8 string located in strings table
+ static const int externalized_string = 23;
+ // the constant pool tag for UTF8 descriptors string located in strings table
+ static const int externalized_string_descriptor = 25;
+ // the constant pool tag for UTF8
+ static const int constant_utf8 = 1;
+ // the constant pool tag for long
+ static const int constant_long = 5;
+ // the constant pool tag for double
+ static const int constant_double = 6;
+ // array index is the constant pool tag. value is size.
+ // eg: array[5] = 8; means size of long is 8 bytes.
+ static const u1 sizes[];
+ // bit 5 and 6 are used to store the length of the compressed integer.
+ // size can be 1 (01), 2 (10), 3 (11).
+ // 0x60 ==> 0110000
+ static const int compressed_index_size_mask = 0x60;
+ /*
+ * mask the length bits (5 and 6) and move to the right 5 bits.
+ */
+ inline static int get_compressed_length(char c) { return ((char) (c & compressed_index_size_mask) >> 5); }
+ inline static bool is_compressed(signed char b1) { return b1 < 0; }
+ static int decompress_int(unsigned char*& value);
+public:
+ SharedStringDecompressor(const char* sym) : ImageDecompressor(sym){}
+ void decompress_resource(u1* data, u1* uncompressed, ResourceHeader* header,
+ const ImageStrings* strings);
+};
+#endif // LIBJIMAGE_IMAGEDECOMPRESSOR_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/imageFile.cpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,682 @@
+/*
+ * 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 <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "endian.hpp"
+#include "imageDecompressor.hpp"
+#include "imageFile.hpp"
+#include "inttypes.hpp"
+#include "jni.h"
+#include "osSupport.hpp"
+
+// Map the full jimage, only with 64 bit addressing.
+bool MemoryMapImage = sizeof(void *) == 8;
+
+#ifdef WIN32
+const char FileSeparator = '\\';
+#else
+const char FileSeparator = '/';
+#endif
+
+// 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 not signed.
+ return seed & 0x7FFFFFFF;
+}
+
+// Match up a string in a perfect hash table.
+// Returns the index where the name should be.
+// 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 || !length) {
+ 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;
+}
+
+// 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.
+ u1 byte;
+ // Repeat until end header is found.
+ while ((byte = *data)) {
+ // Extract kind from header byte.
+ u1 kind = attribute_kind(byte);
+ assert(kind < ATTRIBUTE_COUNT && "invalid image location attribute");
+ // Extract length of data (in bytes).
+ u1 n = attribute_length(byte);
+ // 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;
+ }
+}
+
+// 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);
+ if (found) {
+ u8 data_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
+ _data = new u1[(size_t)data_size];
+ _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);
+ } else {
+ // No module data present.
+ _data = NULL;
+ _header = NULL;
+ _ptm_redirect = NULL;
+ _ptm_data = NULL;
+ _mtp_redirect = NULL;
+ _mtp_data = NULL;
+ _mtp_packages = NULL;
+ }
+}
+
+// Release module data resource.
+ImageModuleData::~ImageModuleData() {
+ if (_data) {
+ delete _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, FileSeparator);
+ // Trim the path to name and extension.
+ const char* name = slash ? slash + 1 : (char *)image_file_name;
+ // Locate the extension period.
+ const char* dot = strrchr(name, '.');
+ assert(dot && "missing extension on jimage name");
+ // Trim to only base name.
+ int length = (int)(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) {
+ // Test files may contain no module data.
+ if (_data != NULL) {
+ // 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 in a NULL terminated array.
+// Returns NULL if module not found.
+const char** ImageModuleData::module_to_packages(const char* module_name) {
+ // Test files may contain no module data.
+ if (_data != NULL) {
+ // 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.
+ u4 count = data->package_count(_endian);
+ const char** packages = new const char*[count + 1];
+ s4 package_offset = data->package_offset(_endian);
+ for (u4 i = 0; i < count; i++) {
+ u4 package_name_offset = mtp_package(package_offset + i);
+ const char* package_name = get_string(package_name_offset);
+ packages[i] = package_name;
+ }
+ packages[count] = NULL;
+ return packages;
+ }
+ }
+ return NULL;
+}
+
+// Manage a table of open image files. This table allows multiple access points
+// to share an open image.
+ImageFileReaderTable::ImageFileReaderTable() : _count(0), _max(_growth) {
+ _table = new ImageFileReader*[_max];
+}
+
+ImageFileReaderTable::~ImageFileReaderTable() {
+ delete _table;
+}
+
+// Add a new image entry to the table.
+void ImageFileReaderTable::add(ImageFileReader* image) {
+ if (_count == _max) {
+ _max += _growth;
+ _table = static_cast<ImageFileReader**>(realloc(_table, _max * sizeof(ImageFileReader*)));
+ }
+ _table[_count++] = image;
+}
+
+// Remove an image entry from the table.
+void ImageFileReaderTable::remove(ImageFileReader* image) {
+ s4 last = _count - 1;
+ for (s4 i = 0; _count; i++) {
+ if (_table[i] == image) {
+ if (i != last) {
+ _table[i] = _table[last];
+ _count = last;
+ }
+ break;
+ }
+ }
+
+ if (_count != 0 && _count == _max - _growth) {
+ _max -= _growth;
+ _table = static_cast<ImageFileReader**>(realloc(_table, _max * sizeof(ImageFileReader*)));
+ }
+}
+
+// Determine if image entry is in table.
+bool ImageFileReaderTable::contains(ImageFileReader* image) {
+ for (s4 i = 0; _count; i++) {
+ if (_table[i] == image) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Table to manage multiple opens of an image file.
+ImageFileReaderTable ImageFileReader::_reader_table;
+
+SimpleCriticalSection _reader_table_lock;
+
+// Open an image file, reuse structure if file already open.
+ImageFileReader* ImageFileReader::open(const char* name, bool big_endian) {
+ {
+ // Lock out _reader_table.
+ SimpleCriticalSectionLock cs(&_reader_table_lock);
+ // Search for an exist image file.
+ for (u4 i = 0; i < _reader_table.count(); i++) {
+ // Retrieve table entry.
+ ImageFileReader* reader = _reader_table.get(i);
+ // If name matches, then reuse (bump up use count.)
+ if (strcmp(reader->name(), name) == 0) {
+ reader->inc_use();
+ return reader;
+ }
+ }
+ } // Unlock the mutex
+
+ // Need a new image reader.
+ ImageFileReader* reader = new ImageFileReader(name, big_endian);
+ bool opened = reader->open();
+ // If failed to open.
+ if (!opened) {
+ delete reader;
+ return NULL;
+ }
+
+ // Lock to update
+ SimpleCriticalSectionLock cs(&_reader_table_lock);
+ // Search for an exist image file.
+ for (u4 i = 0; i < _reader_table.count(); i++) {
+ // Retrieve table entry.
+ ImageFileReader* existing_reader = _reader_table.get(i);
+ // If name matches, then reuse (bump up use count.)
+ if (strcmp(existing_reader->name(), name) == 0) {
+ existing_reader->inc_use();
+ reader->close();
+ delete reader;
+ return existing_reader;
+ }
+ }
+ // Bump use count and add to table.
+ reader->inc_use();
+ _reader_table.add(reader);
+ return reader;
+}
+
+// Close an image file if the file is not in use elsewhere.
+void ImageFileReader::close(ImageFileReader *reader) {
+ // Lock out _reader_table.
+ SimpleCriticalSectionLock cs(&_reader_table_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.
+ SimpleCriticalSectionLock cs(&_reader_table_lock);
+ return _reader_table.contains((ImageFileReader*)id);
+}
+
+// Return an id for the specifed ImageFileReader.
+ImageFileReader* ImageFileReader::idToReader(u8 id) {
+ assert(idCheck(id) && "invalid image id");
+ return (ImageFileReader*)id;
+}
+
+// Constructor intializes to a closed state.
+ImageFileReader::ImageFileReader(const char* name, bool big_endian) {
+ // Copy the image file name.
+ int len = (int) strlen(name) + 1;
+ _name = new char[len];
+ strncpy(_name, name, len);
+ // Initialize for a closed file.
+ _fd = -1;
+ _endian = Endian::get_handler(big_endian);
+ _index_data = NULL;
+}
+
+// Close image and free up data structures.
+ImageFileReader::~ImageFileReader() {
+ // Ensure file is closed.
+ close();
+ // Free up name.
+ if (_name) {
+ delete _name;
+ _name = NULL;
+ }
+}
+
+// Open image file for read access.
+bool ImageFileReader::open() {
+ char buffer[IMAGE_MAX_PATH];
+
+ // If file exists open for reading.
+ _fd = osSupport::openReadOnly(_name);
+ if (_fd == -1) {
+ return false;
+ }
+ // Retrieve the file size.
+ _file_size = osSupport::size(_name);
+ // 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;
+ }
+ // Size of image index.
+ _index_size = index_size();
+ // Make sure file is large enough to contain the index.
+ if (_file_size < _index_size) {
+ return false;
+ }
+ // Determine how much of the image is memory mapped.
+ size_t map_size = (size_t)(MemoryMapImage ? _file_size : _index_size);
+ // Memory map image (minimally the index.)
+ _index_data = (u1*)osSupport::map_memory(_fd, _name, 0, map_size);
+ assert(_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;
+
+ // Initialize the module data
+ ImageModuleData::module_data_name(buffer, _name);
+ module_data = new ImageModuleData(this, buffer);
+ // Successful open.
+ return true;
+}
+
+// Close image file.
+void ImageFileReader::close() {
+ // Deallocate the index.
+ if (_index_data) {
+ osSupport::unmap_memory((char*)_index_data, _index_size);
+ _index_data = NULL;
+ }
+ // Close file.
+ if (_fd != -1) {
+ osSupport::close(_fd);
+ _fd = -1;
+ }
+}
+
+// Read directly from the file.
+bool ImageFileReader::read_at(u1* data, u8 size, u8 offset) const {
+ return (u8)osSupport::read(_fd, (char*)data, size, offset) == size;
+}
+
+// Find the location attributes associated with the path. Returns true if
+// the location is found, false otherwise.
+bool ImageFileReader::find_location(const char* path, ImageLocation& location) const {
+ // Locate the entry in the index perfect hash table.
+ s4 index = ImageStrings::find(_endian, path, _redirect_table, table_length());
+ // If is found.
+ if (index != ImageStrings::NOT_FOUND) {
+ // Get address of first byte of location attribute stream.
+ u1* data = get_location_data(index);
+ // Expand location attributes.
+ location.set_data(data);
+ // Make sure result is not a false positive.
+ return verify_location(location, path);
+ }
+ return false;
+}
+
+// Find the location index and size associated with the path.
+// Returns the location index and size if the location is found, 0 otherwise.
+u4 ImageFileReader::find_location_index(const char* path, u8 *size) const {
+ // Locate the entry in the index perfect hash table.
+ s4 index = ImageStrings::find(_endian, path, _redirect_table, table_length());
+ // If found.
+ if (index != ImageStrings::NOT_FOUND) {
+ // Get address of first byte of location attribute stream.
+ u4 offset = get_location_offset(index);
+ u1* data = get_location_offset_data(offset);
+ // Expand location attributes.
+ ImageLocation location(data);
+ // Make sure result is not a false positive.
+ if (verify_location(location, path)) {
+ *size = (jlong)location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
+ return offset;
+ }
+ }
+ return 0; // not found
+}
+
+// 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.
+ assert(next - path + length + 2 < max && "buffer overflow");
+ // Append '/module/'.
+ *next++ = '/';
+ strncpy(next, module, length); next += length;
+ *next++ = '/';
+ }
+ // 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.
+ assert(next - path + length + 1 < max && "buffer overflow");
+ // Append 'patent/' .
+ strncpy(next, parent, length); 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.
+ assert(next - path + length < max && "buffer overflow");
+ // Append base name.
+ strncpy(next, base, length); 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.
+ assert(next - path + length + 1 < max && "buffer overflow");
+ // Append '.extension' .
+ *next++ = '.';
+ strncpy(next, extension, length); next += length;
+ }
+ // Make sure there is no buffer overflow.
+ assert((size_t)(next - path) < max && "buffer overflow");
+ // Terminate string.
+ *next = '\0';
+}
+
+// Verify that a found location matches the supplied path (without copying.)
+bool ImageFileReader::verify_location(ImageLocation& location, const char* path) const {
+ // Manage the image string table.
+ ImageStrings strings(_string_bytes, _header.strings_size(_endian));
+ // Position to first character of the path string.
+ const char* next = path;
+ // Get module name string.
+ const char* module = location.get_attribute(ImageLocation::ATTRIBUTE_MODULE, strings);
+ // If module string is not empty.
+ if (*module != '\0') {
+ // Compare '/module/' .
+ if (*next++ != '/') return false;
+ if (!(next = ImageStrings::starts_with(next, module))) return false;
+ if (*next++ != '/') return false;
+ }
+ // Get parent (package) string
+ const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);
+ // If parent string is not empty string.
+ if (*parent != '\0') {
+ // Compare 'parent/' .
+ if (!(next = ImageStrings::starts_with(next, parent))) return false;
+ if (*next++ != '/') return false;
+ }
+ // Get base name string.
+ const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings);
+ // Compare with basne name.
+ if (!(next = ImageStrings::starts_with(next, base))) return false;
+ // Get extension string.
+ const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);
+ // If extension is not empty.
+ if (*extension != '\0') {
+ // Compare '.extension' .
+ if (*next++ != '.') return false;
+ if (!(next = ImageStrings::starts_with(next, extension))) return false;
+ }
+ // True only if complete match and no more characters.
+ return *next == '\0';
+}
+
+// Return the resource for the supplied location offset.
+void ImageFileReader::get_resource(u4 offset, u1* uncompressed_data) const {
+ // Get address of first byte of location attribute stream.
+ u1* data = get_location_offset_data(offset);
+ // Expand location attributes.
+ ImageLocation location(data);
+ // Read the data
+ get_resource(location, uncompressed_data);
+}
+
+// Return the resource 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 the resource is compressed.
+ if (compressed_size != 0) {
+ u1* compressed_data;
+ // If not memory mapped read in bytes.
+ if (!MemoryMapImage) {
+ // Allocate buffer for compression.
+ compressed_data = new u1[(u4)compressed_size];
+ // Read bytes from offset beyond the image index.
+ bool is_read = read_at(compressed_data, compressed_size, _index_size + offset);
+ assert(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, (u4)uncompressed_size,
+ &strings);
+ // If not memory mapped then release temporary buffer.
+ if (!MemoryMapImage) {
+ delete compressed_data;
+ }
+ } else {
+ // Read bytes from offset beyond the image index.
+ bool is_read = read_at(uncompressed_data, uncompressed_size, _index_size + offset);
+ assert(is_read && "error reading from image or short read");
+ }
+}
+
+// Return the ImageModuleData for this image
+ImageModuleData * ImageFileReader::get_image_module_data() {
+ return module_data;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/imageFile.hpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,648 @@
+/*
+ * Copyright (c) 2014, 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 LIBJIMAGE_IMAGEFILE_HPP
+#define LIBJIMAGE_IMAGEFILE_HPP
+
+#include <assert.h>
+
+#include "endian.hpp"
+#include "inttypes.hpp"
+
+// Image files are an alternate file format for storing classes and resources. The
+// goal is to supply file access which is faster and smaller than the jar format.
+// 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;
+//
+// +-----------+
+// | Header |
+// +-----------+
+// | |
+// | Index |
+// | |
+// +-----------+
+// | |
+// | |
+// | Resources |
+// | |
+// | |
+// +-----------+
+//
+// The header contains information related to identification and description of
+// contents.
+//
+// +-------------------------+
+// | Magic (0xCAFEDADA) |
+// +------------+------------+
+// | Major Vers | Minor Vers |
+// +------------+------------+
+// | Flags |
+// +-------------------------+
+// | Resource Count |
+// +-------------------------+
+// | Table Length |
+// +-------------------------+
+// | Attributes Size |
+// +-------------------------+
+// | Strings Size |
+// +-------------------------+
+//
+// Magic - means of identifying validity of the file. This avoids requiring a
+// special file extension.
+// Major vers, minor vers - differences in version numbers indicate structural
+// changes in the image.
+// 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
+// index and meta data.
+//
+// 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 /<module>/<package>/<base>.<extension> return the resource location
+// information;
+//
+// redirectIndex = hash(path, DEFAULT_SEED) % table_length;
+// redirect = redirectTable[redirectIndex];
+// if (redirect == 0) return not found;
+// locationIndex = redirect < 0 ? -1 - redirect : hash(path, redirect) % table_length;
+// location = locationTable[locationIndex];
+// if (!verify(location, path)) return not found;
+// return location;
+//
+// Note: The hash function takes an initial seed value. A different seed value
+// usually returns a different result for strings that would otherwise collide with
+// 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 index;
+//
+// +-------------------+
+// | Redirect Table |
+// +-------------------+
+// | Attribute Offsets |
+// +-------------------+
+// | Attribute Data |
+// +-------------------+
+// | Strings |
+// +-------------------+
+//
+// Redirect Table - Array of 32-bit signed values representing actions that
+// should take place for hashed strings that map to that
+// value. Negative values indicate no hash collision and can be
+// quickly converted to indices into attribute offsets. Positive
+// values represent a new seed for hashing an index into attribute
+// 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. 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 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 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 {
+private:
+ u1* _data; // Data bytes for strings.
+ u4 _size; // Number of bytes in the string table.
+public:
+ 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");
+ return (const char*)(_data + offset);
+ }
+
+ // 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 s4 hash_code(const char* string, s4 seed);
+
+ // 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 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
+// 'length' less 1 (lower 3 bits of header) of bytes that follow containing the
+// attribute value. Attribute values present as most significant byte first.
+//
+// Ex. Container offset (ATTRIBUTE_OFFSET) 0x33562 would be represented as 0x22
+// (kind = 4, length = 3), 0x03, 0x35, 0x62.
+//
+// An attribute stream is terminated with a header kind of ATTRIBUTE_END (header
+// byte of zero.)
+//
+// ImageLocation inflates the stream into individual values stored in the long
+// array _attributes. This allows an attribute value can be quickly accessed by
+// direct indexing. Unspecified values default to zero.
+//
+// Notes:
+// - Even though ATTRIBUTE_END is used to mark the end of the attribute stream,
+// streams will contain zero byte values to represent lesser significant bits.
+// Thus, detecting a zero byte is not sufficient to detect the end of an attribute
+// 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 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
+// inflated resource in memory. If the ATTRIBUTE_COMPRESSED is zero then the value
+// of ATTRIBUTE_UNCOMPRESSED represents both the number of bytes in the image and
+// in memory. In the future, additional compression techniques will be used and
+// represented differently.
+// - Package strings include trailing slash and extensions include prefix period.
+//
+class ImageLocation {
+public:
+ 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.
+ u8 _attributes[ATTRIBUTE_COUNT];
+
+ // Return the attribute value number of bytes.
+ inline static u1 attribute_length(u1 data) {
+ return (data & 0x7) + 1;
+ }
+
+ // Return the attribute kind.
+ inline static u1 attribute_kind(u1 data) {
+ u1 kind = data >> 3;
+ assert(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");
+ u8 value = 0;
+ // Most significant bytes first.
+ for (u1 i = 0; i < n; i++) {
+ value <<= 8;
+ value |= data[i];
+ }
+ return value;
+ }
+
+public:
+ 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");
+ return _attributes[kind];
+ }
+
+ // Retrieve an attribute string value from the inflated array.
+ inline const char* get_attribute(u4 kind, const ImageStrings& strings) const {
+ return strings.get((u4)get_attribute(kind));
+ }
+};
+
+//
+// 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 {
+ class Header {
+ 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); }
+ };
+
+ // Hashtable entry
+ class HashData {
+ private:
+ u4 _name_offset; // Name offset in string table
+ public:
+ inline s4 name_offset(Endian* endian) const { return endian->get(_name_offset); }
+ };
+
+ // Package to module hashtable entry
+ class PTMData : public HashData {
+ private:
+ u4 _module_name_offset; // Module name offset in string table
+ public:
+ inline s4 module_name_offset(Endian* endian) const { return endian->get(_module_name_offset); }
+ };
+
+ // Module to package hashtable entry
+ class MTPData : public HashData {
+ private:
+ u4 _package_count; // Number of packages in module
+ u4 _package_offset; // Offset in package list
+ public:
+ inline u4 package_count(Endian* endian) const { return endian->get(_package_count); }
+ inline u4 package_offset(Endian* endian) const { return endian->get(_package_offset); }
+ };
+
+ const ImageFileReader* _image_file; // Source image file
+ Endian* _endian; // Endian handler
+ ImageStrings _strings; // Image file strings
+ u1* _data; // Module data resource data
+ u8 _data_size; // Size of resource data
+ Header* _header; // Module data header
+ s4* _ptm_redirect; // Package to module hashtable redirect
+ PTMData* _ptm_data; // Package to module data
+ s4* _mtp_redirect; // Module to packages hashtable redirect
+ MTPData* _mtp_data; // Module to packages data
+ s4* _mtp_packages; // Package data (name offsets)
+
+ // Return a string from the string table.
+ inline const char* get_string(u4 offset) {
+ return _strings.get(offset);
+ }
+
+ inline u4 mtp_package(u4 index) {
+ return _endian->get(_mtp_packages[index]);
+ }
+
+public:
+ ImageModuleData(const ImageFileReader* image_file, const char* module_data_name);
+ ~ImageModuleData();
+
+ // Return the name of the module data resource.
+ static void module_data_name(char* buffer, const char* image_file_name);
+
+ // Return the module in which a package resides. Returns NULL if not found.
+ const char* package_to_module(const char* package_name);
+
+ // Returns all the package names in a module in a NULL terminated array.
+ // Returns NULL if module not found.
+ const char** module_to_packages(const char* module_name);
+};
+
+// Image file header, starting at offset 0.
+class ImageHeader {
+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
+
+class ImageFileReader;
+
+// Manage a table of open image files. This table allows multiple access points
+// to share an open image.
+class ImageFileReaderTable {
+private:
+ const static u4 _growth = 8; // Growth rate of the table
+ u4 _count; // Number of entries in the table
+ u4 _max; // Maximum number of entries allocated
+ ImageFileReader** _table; // Growable array of entries
+
+public:
+ ImageFileReaderTable();
+ ~ImageFileReaderTable();
+
+ // Return the number of entries.
+ inline u4 count() { return _count; }
+
+ // Return the ith entry from the table.
+ inline ImageFileReader* get(u4 i) { return _table[i]; }
+
+ // Add a new image entry to the table.
+ void add(ImageFileReader* image);
+
+ // Remove an image entry from the table.
+ void remove(ImageFileReader* image);
+
+ // Determine if image entry is in table.
+ bool contains(ImageFileReader* image);
+};
+
+// 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 {
+private:
+ // Manage a number of image files such that an image can be shared across
+ // multiple uses (ex. loader.)
+ static ImageFileReaderTable _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
+ ImageModuleData *module_data; // The ImageModuleData for this image
+
+ ImageFileReader(const char* name, bool big_endian);
+ ~ImageFileReader();
+
+ // Compute number of bytes in image file index.
+ inline size_t index_size() {
+ return sizeof(ImageHeader) +
+ table_length() * sizeof(u4) * 2 + locations_size() + strings_size();
+ }
+
+public:
+ 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());
+
+ // 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(_endian));
+ }
+
+ // Return location attribute stream at offset.
+ inline u1* get_location_offset_data(u4 offset) const {
+ assert((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 index) const {
+ return get_location_offset_data(get_location_offset(index));
+ }
+
+ // Return the location offset for index.
+ inline u4 get_location_offset(u4 index) const {
+ assert((u4)index < _header.table_length(_endian) &&
+ "index exceeds location count");
+ return _endian->get(_offsets_table[index]);
+ }
+
+ // 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;
+
+ // Find the location index and size associated with the path.
+ // Returns the location index and size if the location is found,
+ // ImageFileReader::NOT_FOUND otherwise.
+ u4 find_location_index(const char* path, u8 *size) 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 index.
+ void get_resource(u4 index, u1* uncompressed_data) const;
+
+ // Return the resource for the supplied path.
+ void get_resource(ImageLocation& location, u1* uncompressed_data) const;
+
+ // Return the ImageModuleData for this image
+ ImageModuleData * get_image_module_data();
+
+};
+#endif // LIBJIMAGE_IMAGEFILE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/inttypes.hpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,43 @@
+/*
+ * 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 LIBJIMAGE_INTTYPES_HPP
+#define LIBJIMAGE_INTTYPES_HPP
+
+typedef unsigned char u1;
+typedef char s1;
+typedef unsigned short u2;
+typedef short s2;
+typedef unsigned int u4;
+typedef int s4;
+#ifdef LP64
+typedef unsigned long u8;
+typedef long s8;
+#else
+typedef unsigned long long u8;
+typedef long long s8;
+#endif
+
+#endif // LIBJIMAGE_INTTYPES_HPP
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/jimage.cpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2014, 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 <string.h>
+
+#include "jimage.hpp"
+
+#include "imageFile.hpp"
+
+#define BOOT_VERSION "9.0"
+
+/*
+ * JImageOpen - Given the supplied full path file name, open an image file. This
+ * function will also initialize tables and retrieve meta-data necessary to
+ * satisfy other functions in the API. If the image file has been previously
+ * open, a new open request will share memory and resources used by the previous
+ * open. A call to JImageOpen should be balanced by a call to JImageClose, to
+ * release memory and resources used. If the image file is not found or cannot
+ * be open, then NULL is returned and error will contain a reason for the
+ * failure; a positive value for a system error number, negative for a jimage
+ * specific error (see JImage Error Codes.)
+ *
+ * Ex.
+ * jint error;
+ * JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules/bootmodules.jimage", &error);
+ * if (image == NULL) {
+ * tty->print_cr("JImage failed to open: %d", error);
+ * ...
+ * }
+ * ...
+ */
+extern "C" JImageFile* JIMAGE_Open(const char *name, jint* error) {
+ // TODO - return a meaningful error code
+ *error = 0;
+ ImageFileReader* jfile = ImageFileReader::open(name);
+ return (JImageFile*) jfile;
+}
+
+/*
+ * JImageClose - Given the supplied open image file (see JImageOpen), release
+ * memory and resources used by the open file and close the file. If the image
+ * file is shared by other uses, release and close is deferred until the last use
+ * is also closed.
+ *
+ * Ex.
+ * (*JImageClose)(image);
+ */
+extern "C" void JIMAGE_Close(JImageFile* image) {
+ ImageFileReader::close((ImageFileReader*) image);
+}
+
+/*
+ * JImagePackageToModule - Given an open image file (see JImageOpen) and the name
+ * of a package, return the name of module where the package resides. If the
+ * package does not exist in the image file, the function returns NULL.
+ * The resulting string does/should not have to be released. All strings are
+ * utf-8, zero byte terminated.
+ *
+ * Ex.
+ * const char* package = (*JImagePackageToModule)(image, "java/lang");
+ * tty->print_cr(package);
+ * —> java.base
+ */
+extern "C" const char* JIMAGE_PackageToModule(JImageFile* image, const char* package_name) {
+ return ((ImageFileReader*) image)->get_image_module_data()->package_to_module(package_name);
+}
+
+/*
+ * JImageFindResource - Given an open image file (see JImageOpen), a module
+ * name, a version string and the name of a class/resource, return location
+ * information describing the resource and its size. If no resource is found, the
+ * function returns JIMAGE_NOT_FOUND and the value of size is undefined.
+ * The version number should be "9.0" and is not used in locating the resource.
+ * The resulting location does/should not have to be released.
+ * All strings are utf-8, zero byte terminated.
+ *
+ * Ex.
+ * jlong size;
+ * JImageLocationRef location = (*JImageFindResource)(image, "java.base", "9.0", "java/lang/String.class", &size);
+ */
+extern "C" JImageLocationRef JIMAGE_FindResource(JImageFile* image,
+ const char* module_name, const char* version, const char* name,
+ jlong* size) {
+ if (strcmp(version, BOOT_VERSION) != 0) {
+ return (JImageLocationRef) 0;
+ }
+
+ ImageLocation location;
+ char fullpath[IMAGE_MAX_PATH];
+
+ // Concatenate to get full path
+ strncpy(fullpath, "/", IMAGE_MAX_PATH - 1);
+ strncat(fullpath, module_name, IMAGE_MAX_PATH - 1);
+ strncat(fullpath, "/", IMAGE_MAX_PATH - 1);
+ strncat(fullpath, name, IMAGE_MAX_PATH - 1);
+ JImageLocationRef loc =
+ (JImageLocationRef) ((ImageFileReader*) image)->find_location_index(fullpath, (u8*) size);
+ return loc;
+}
+
+/*
+ * JImageGetResource - Given an open image file (see JImageOpen), a resource’s
+ * location information (see JImageFindResource), a buffer of appropriate
+ * size and the size, retrieve the bytes associated with the
+ * resource. If the size is less than the resource size then the read is truncated.
+ * If the size is greater than the resource size then the remainder of the buffer
+ * is zero filled. The function will return the actual size of the resource.
+ *
+ * Ex.
+ * jlong size;
+ * JImageLocationRef* location = (*JImageFindResource)(image, "java.base", "9.0", "java/lang/String.class", &size);
+ * char* buffer = new char[size];
+ * (*JImageGetResource)(image, location, buffer, size);
+ */
+extern "C" jlong JIMAGE_GetResource(JImageFile* image, JImageLocationRef location,
+ char* buffer, jlong size) {
+ ((ImageFileReader*) image)->get_resource((u4) location, (u1*) buffer);
+ return size;
+}
+
+/*
+ * JImageResourceIterator - Given an open image file (see JImageOpen), a visitor
+ * function and a visitor argument, iterator through each of the image's resources.
+ * The visitor function is called with the image file, the module name, the
+ * package name, the base name, the extension and the visitor argument. The return
+ * value of the visitor function should be true, unless an early iteration exit is
+ * required. All strings are utf-8, zero byte terminated.file.
+ *
+ * Ex.
+ * bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version, const char* package, const char* name, const char* extension, void* arg) {
+ * if (strcmp(extension, “class”) == 0) {
+ * char path[JIMAGE_MAX_PATH];
+ * Thread* THREAD = Thread::current();
+ * jio_snprintf(path, JIMAGE_MAX_PATH - 1, "/%s/%s", package, name);
+ * ClassLoader::compile_the_world_in(path, (Handle)arg, THREAD);
+ * return !HAS_PENDING_EXCEPTION;
+ * }
+ * return true;
+ * }
+ * (*JImageResourceIterator)(image, ctw_visitor, loader);
+ */
+extern "C" void JIMAGE_ResourceIterator(JImageFile* image,
+ JImageResourceVisitor_t visitor, void* arg) {
+ ImageFileReader* imageFile = (ImageFileReader*) image;
+ u4 nEntries = imageFile->table_length();
+ const ImageStrings strings = imageFile->get_strings();
+ for (u4 i = 0; i < nEntries; i++) {
+ ImageLocation location(imageFile->get_location_data(i));
+
+ u4 moduleOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_MODULE);
+ if (moduleOffset == 0) {
+ continue; // skip non-modules
+ }
+ const char *module = strings.get(moduleOffset);
+ if (strcmp(module, "modules") == 0
+ || strcmp(module, "packages") == 0) {
+ continue; // always skip
+ }
+
+ u4 parentOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_PARENT);
+ const char *parent = strings.get(parentOffset);
+ u4 baseOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_BASE);
+ const char *base = strings.get(baseOffset);
+ u4 extOffset = (u4) location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION);
+ const char *extension = strings.get(extOffset);
+
+ if (!(*visitor)(image, module, "9", parent, base, extension, arg)) {
+ break;
+ }
+
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/jimage.hpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,176 @@
+/*
+ * 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 "jni.h"
+
+// Opaque reference to a JImage file.
+class JImageFile;
+// Opaque reference to an image file resource location.
+typedef jlong JImageLocationRef;
+
+// 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 JIMAGE_MAX_PATH 4096
+
+// JImage Error Codes
+
+// The image file is not prefixed with 0xCAFEDADA
+#define JIMAGE_BAD_MAGIC (-1)
+// The image file does not have a compatible (translatable) version
+#define JIMAGE_BAD_VERSION (-2)
+// The image file content is malformed
+#define JIMAGE_CORRUPTED (-3)
+
+/*
+ * JImageOpen - Given the supplied full path file name, open an image file. This
+ * function will also initialize tables and retrieve meta-data necessary to
+ * satisfy other functions in the API. If the image file has been previously
+ * open, a new open request will share memory and resources used by the previous
+ * open. A call to JImageOpen should be balanced by a call to JImageClose, to
+ * release memory and resources used. If the image file is not found or cannot
+ * be open, then NULL is returned and error will contain a reason for the
+ * failure; a positive value for a system error number, negative for a jimage
+ * specific error (see JImage Error Codes.)
+ *
+ * Ex.
+ * jint error;
+ * JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules/bootmodules.jimage", &error);
+ * if (image == NULL) {
+ * tty->print_cr("JImage failed to open: %d", error);
+ * ...
+ * }
+ * ...
+ */
+
+extern "C" JImageFile* JIMAGE_Open(const char *name, jint* error);
+
+typedef JImageFile* (*JImageOpen_t)(const char *name, jint* error);
+
+/*
+ * JImageClose - Given the supplied open image file (see JImageOpen), release
+ * memory and resources used by the open file and close the file. If the image
+ * file is shared by other uses, release and close is deferred until the last use
+ * is also closed.
+ *
+ * Ex.
+ * (*JImageClose)(image);
+ */
+
+extern "C" void JIMAGE_Close(JImageFile* jimage);
+
+typedef void (*JImageClose_t)(JImageFile* jimage);
+
+
+/*
+ * JImagePackageToModule - Given an open image file (see JImageOpen) and the name
+ * of a package, return the name of module where the package resides. If the
+ * package does not exist in the image file, the function returns NULL.
+ * The resulting string does/should not have to be released. All strings are
+ * utf-8, zero byte terminated.
+ *
+ * Ex.
+ * const char* package = (*JImagePackageToModule)(image, "java/lang");
+ * tty->print_cr(package);
+ * —> java.base
+ */
+
+extern "C" const char * JIMAGE_PackageToModule(JImageFile* jimage, const char* package_name);
+
+typedef const char* (*JImagePackageToModule_t)(JImageFile* jimage, const char* package_name);
+
+
+/*
+ * JImageFindResource - Given an open image file (see JImageOpen), a module
+ * name, a version string and the name of a class/resource, return location
+ * information describing the resource and its size. If no resource is found, the
+ * function returns JIMAGE_NOT_FOUND and the value of size is undefined.
+ * The version number should be "9.0" and is not used in locating the resource.
+ * The resulting location does/should not have to be released.
+ * All strings are utf-8, zero byte terminated.
+ *
+ * Ex.
+ * jlong size;
+ * JImageLocationRef location = (*JImageFindResource)(image, "java.base", "9.0", "java/lang/String.class", &size);
+ */
+extern "C" JImageLocationRef JIMAGE_FindResource(JImageFile* jimage,
+ const char* module_name, const char* version, const char* name,
+ jlong* size);
+
+typedef JImageLocationRef(*JImageFindResource_t)(JImageFile* jimage,
+ const char* module_name, const char* version, const char* name,
+ jlong* size);
+
+
+/*
+ * JImageGetResource - Given an open image file (see JImageOpen), a resource’s
+ * location information (see JImageFindResource), a buffer of appropriate
+ * size and the size, retrieve the bytes associated with the
+ * resource. If the size is less than the resource size then the read is truncated.
+ * If the size is greater than the resource size then the remainder of the buffer
+ * is zero filled. The function will return the actual size of the resource.
+ *
+ * Ex.
+ * jlong size;
+ * JImageLocationRef location = (*JImageFindResource)(image, "java.base", "9.0", "java/lang/String.class", &size);
+ * char* buffer = new char[size];
+ * (*JImageGetResource)(image, location, buffer, size);
+ */
+extern "C" jlong JIMAGE_GetResource(JImageFile* jimage, JImageLocationRef location,
+ char* buffer, jlong size);
+
+typedef jlong(*JImageGetResource_t)(JImageFile* jimage, JImageLocationRef location,
+ char* buffer, jlong size);
+
+
+/*
+ * JImageResourceIterator - Given an open image file (see JImageOpen), a visitor
+ * function and a visitor argument, iterator through each of the image's resources.
+ * The visitor function is called with the image file, the module name, the
+ * package name, the base name, the extension and the visitor argument. The return
+ * value of the visitor function should be true, unless an early iteration exit is
+ * required. All strings are utf-8, zero byte terminated.file.
+ *
+ * Ex.
+ * bool ctw_visitor(JImageFile* jimage, const char* module_name, const char* version, const char* package, const char* name, const char* extension, void* arg) {
+ * if (strcmp(extension, “class”) == 0) {
+ * char path[JIMAGE_MAX_PATH];
+ * Thread* THREAD = Thread::current();
+ * jio_snprintf(path, JIMAGE_MAX_PATH - 1, "/%s/%s", package, name);
+ * ClassLoader::compile_the_world_in(path, (Handle)arg, THREAD);
+ * return !HAS_PENDING_EXCEPTION;
+ * }
+ * return true;
+ * }
+ * (*JImageResourceIterator)(image, ctw_visitor, loader);
+ */
+
+typedef bool (*JImageResourceVisitor_t)(JImageFile* jimage,
+ const char* module_name, const char* version, const char* package,
+ const char* name, const char* extension, void* arg);
+
+extern "C" void JIMAGE_ResourceIterator(JImageFile* jimage,
+ JImageResourceVisitor_t visitor, void *arg);
+
+typedef void (*JImageResourceIterator_t)(JImageFile* jimage,
+ JImageResourceVisitor_t visitor, void* arg);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libjimage/osSupport.hpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,109 @@
+/*
+ * 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 LIBJIMAGE_OSSUPPORT_HPP
+#define LIBJIMAGE_OSSUPPORT_HPP
+
+#ifdef WIN32
+#include <Windows.h>
+#else
+#include <pthread.h>
+#endif
+
+class osSupport {
+public:
+ /**
+ * Open a regular file read-only.
+ * Return the file descriptor.
+ */
+ static jint openReadOnly(const char *path);
+
+ /**
+ * Close a file descriptor.
+ */
+ static jint close(jint fd);
+
+ /**
+ * Return the size of a regular file.
+ */
+ static jlong size(const char *path);
+
+ /**
+ * Read nBytes at offset into a buffer.
+ */
+ static jlong read(jint fd, char *buf, jlong nBytes, jlong offset);
+
+ /**
+ * Map nBytes at offset into memory and return the address.
+ * The system chooses the address.
+ */
+ static void* map_memory(jint fd, const char *filename, size_t file_offset, size_t bytes);
+
+ /**
+ * Unmap nBytes of memory at address.
+ */
+ static int unmap_memory(void* addr, size_t bytes);
+};
+
+/**
+ * A CriticalSection to protect a small section of code.
+ */
+class SimpleCriticalSection {
+ friend class SimpleCriticalSectionLock;
+private:
+ void enter();
+ void exit();
+public:
+ SimpleCriticalSection();
+ //~SimpleCriticalSection(); // Cretes a dependency on Solaris on a C++ exit registration
+
+private:
+#ifdef WIN32
+ CRITICAL_SECTION critical_section;
+#else
+ pthread_mutex_t mutex;
+#endif // WIN32
+};
+
+/**
+ * SimpleCriticalSectionLock instance.
+ * The constructor locks a SimpleCriticalSection and the
+ * destructor does the unlock.
+ */
+class SimpleCriticalSectionLock {
+private:
+ SimpleCriticalSection *lock;
+public:
+
+ SimpleCriticalSectionLock(SimpleCriticalSection *cslock) {
+ this->lock = cslock;
+ lock->enter();
+ }
+
+ ~SimpleCriticalSectionLock() {
+ lock->exit();
+ }
+};
+
+#endif // LIBJIMAGE_OSSUPPORT_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/unix/native/libjimage/osSupport_unix.cpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,111 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "jni.h"
+#include "osSupport.hpp"
+
+/**
+ * Open a regular file read-only.
+ * Return the file descriptor.
+ */
+jint osSupport::openReadOnly(const char *path) {
+ return ::open(path, 0);
+}
+
+/**
+ * Close a file descriptor.
+ */
+jint osSupport::close(jint fd) {
+ return ::close(fd);
+}
+
+/**
+ * Return the size of a regular file.
+ */
+jlong osSupport::size(const char *path) {
+ struct stat statbuf;
+ if (stat(path, &statbuf) < 0 ||
+ (statbuf.st_mode & S_IFREG) != S_IFREG) {
+ return -1;
+ }
+ return (jsize) statbuf.st_size;
+}
+
+/**
+ * Read nBytes at offset into a buffer.
+ */
+jlong osSupport::read(jint fd, char *buf, jlong nBytes, jlong offset) {
+ return ::pread(fd, buf, nBytes, offset);
+}
+
+/**
+ * Map nBytes at offset into memory and return the address.
+ * The system chooses the address.
+ */
+void* osSupport::map_memory(int fd, const char *filename, size_t file_offset, size_t bytes) {
+ void* mapped_address = NULL;
+ mapped_address = (void*) mmap(NULL,
+ bytes, PROT_READ, MAP_SHARED,
+ fd, file_offset);
+ if (mapped_address == MAP_FAILED) {
+ return NULL;
+ }
+ return mapped_address;
+}
+
+/**
+ * Unmap nBytes of memory at address.
+ */
+int osSupport::unmap_memory(void *addr, size_t bytes) {
+ return munmap((char *) addr, bytes) == 0;
+}
+
+/**
+ * A CriticalSection to protect a small section of code.
+ */
+void SimpleCriticalSection::enter() {
+ pthread_mutex_lock(&mutex);
+}
+
+void SimpleCriticalSection::exit() {
+ pthread_mutex_unlock(&mutex);
+
+}
+
+SimpleCriticalSection::SimpleCriticalSection() {
+ pthread_mutex_init(&mutex, NULL);
+}
+
+//SimpleCriticalSection::~SimpleCriticalSection() {
+// pthread_mutex_destroy(&mutex);
+//}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/windows/native/libjimage/osSupport_windows.cpp Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,133 @@
+/*
+ * 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 <windows.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <io.h>
+#include <malloc.h>
+
+#include "jni.h"
+#include "osSupport.hpp"
+
+/**
+ * Open a regular file read-only.
+ * Return the file descriptor.
+ */
+jint osSupport::openReadOnly(const char *path) {
+ return ::open(path, 0, 0);
+}
+
+/**
+ * Close a file descriptor.
+ */
+jint osSupport::close(jint fd) {
+ return ::close(fd);
+}
+
+/**
+ * Return the size of a regular file.
+ */
+jlong osSupport::size(const char *path) {
+ struct stat statbuf;
+ if (stat(path, &statbuf) < 0 ||
+ (statbuf.st_mode & S_IFREG) != S_IFREG) {
+ return -1;
+ }
+ return (jlong) statbuf.st_size;
+}
+
+/**
+ * Read nBytes at offset into a buffer.
+ */
+jlong osSupport::read(jint fd, char *buf, jlong nBytes, jlong offset) {
+ OVERLAPPED ov;
+ DWORD nread;
+ BOOL result;
+
+ ZeroMemory(&ov, sizeof (ov));
+ ov.Offset = (DWORD) offset;
+ ov.OffsetHigh = (DWORD) (offset >> 32);
+
+ HANDLE h = (HANDLE)::_get_osfhandle(fd);
+
+ result = ReadFile(h, (LPVOID) buf, (DWORD) nBytes, &nread, &ov);
+
+ return result ? nread : 0;
+}
+
+/**
+ * Map nBytes at offset into memory and return the address.
+ * The system chooses the address.
+ */
+void* osSupport::map_memory(jint fd, const char *file_name, size_t file_offset, size_t bytes) {
+ HANDLE hFile;
+ char* base = NULL;
+
+ // Get a handle to the file
+ hFile = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile != NULL) {
+ // Create a file mapping handle
+ HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0,
+ NULL /* file_name */);
+ if (hMap != NULL) {
+ // Map the file into the address space at the offset
+ base = (char*) MapViewOfFileEx(hMap, FILE_MAP_READ, 0, (DWORD) file_offset,
+ (DWORD) bytes, NULL);
+ CloseHandle(hMap); // The mapping is no longer needed
+ }
+ CloseHandle(hFile); // The file handle is no longer needed
+ }
+ return base;
+}
+
+/**
+ * Unmap nBytes of memory at address.
+ */
+int osSupport::unmap_memory(void* addr, size_t bytes) {
+ BOOL result = UnmapViewOfFile(addr);
+ return result;
+}
+
+/**
+ * A CriticalSection to protect a small section of code.
+ */
+void SimpleCriticalSection::enter() {
+ EnterCriticalSection(&critical_section);
+}
+
+void SimpleCriticalSection::exit() {
+ LeaveCriticalSection(&critical_section);
+}
+
+SimpleCriticalSection::SimpleCriticalSection() {
+ InitializeCriticalSection(&critical_section);
+}
+
+//SimpleCriticalSection::~SimpleCriticalSection() {
+// DeleteCriticalSection(&critical_section);
+//}
+
--- a/jdk/test/TEST.groups Mon Aug 31 21:48:00 2015 +0300
+++ b/jdk/test/TEST.groups Fri Sep 04 10:11:43 2015 -0300
@@ -67,6 +67,7 @@
sun/misc \
sun/reflect \
jdk/lambda \
+ jdk/internal/jimage \
vm
# All of the java.util package
@@ -210,13 +211,13 @@
# java launcher specific tests, Note: do not include this group into any groups
# that potentially could be included into a jprt test rule, as the complementary
-# closed group includes awt SplashScreen and these tests may not run
-# satisfacotorily on all platforms and profiles thus this group must always
+# closed group includes awt SplashScreen and these tests may not run
+# satisfactorily on all platforms and profiles thus this group must always
# be a stand-alone group
jdk_launcher = \
tools/launcher \
sun/tools
-
+
#
# Tool (and tool API) tests are split into core and svc groups
#
@@ -473,7 +474,7 @@
sun/reflect/CallerSensitive/MissingCallerSensitive.java \
sun/security/util/Resources/NewNamesFormat.java \
vm/verifier/defaultMethods/DefaultMethodRegressionTestsRun.java \
- javax/xml/ws/clientjar/TestWsImport.java
+ javax/xml/ws/clientjar/TestWsImport.java
# JRE adds further tests to compact3
#
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/jimage/JImageReadTest.java Fri Sep 04 10:11:43 2015 -0300
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+/*
+ * @modules java.base/jdk.internal.jimage
+ * @summary Unit test for libjimage JIMAGE_Open/Read/Close
+ */
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import jdk.internal.jimage.BasicImageReader;
+import jdk.internal.jimage.ImageNativeSubstrate;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Optional;
+import org.testng.annotations.Parameters;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+import org.testng.TestNG;
+
+@Test
+public class JImageReadTest {
+
+ static String javaHome = System.getProperty("java.home");
+ static String imageFile = javaHome + File.separator + "lib"
+ + File.separator + "modules" + File.separator
+ + "bootmodules.jimage";
+
+ @DataProvider(name="classes")
+ static Object[][] loadClasses() {
+ return new Object[][] {
+ {"java.base", "java/lang/String.class"},
+ {"java.base", "java/lang/Object.class"},
+ {"java.base", "sun/reflect/generics/tree/TypeArgument.class"},
+ {"jdk.jdeps", "com/sun/tools/javap/StackMapWriter$StackMapBuilder.class"},
+ {"jdk.hotspot.agent", "sa.properties"},
+ {"java.logging", "java/util/logging/Logger.class"},
+ {"java.base", "java/NOSUCHCLASS/yyy.class"}, // non-existent
+ {"NOSUCHMODULE", "java/lang/Class.class"}, // non-existent
+ };
+ }
+
+
+ @DataProvider(name="packages")
+ static Object[][] loadPackages() {
+ return new Object[][] {
+ {"java.base", "java/lang"},
+ {"java.base", "java/io"},
+ {"java.logging", "java/util/logging"},
+ };
+ }
+
+ /**
+ * Test a class is correctly accessible from the image in a module.
+ *
+ * @param moduleName the module name
+ * @param className the classname
+ * @throws Exception is thrown if there is a test error
+ */
+ @Test(dataProvider="classes")
+ public static void test1_ReadClasses(String moduleName, String className) throws Exception {
+ final int classMagic = 0xCAFEBABE;
+ final long NOT_FOUND = 0L;
+
+ if (!(new File(imageFile)).exists()) {
+ System.out.printf("Test skipped; no jimage file");
+ return;
+ }
+
+ long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
+ Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
+
+ long[] sizeArray = new long[1];
+ long locationHandle =
+ ImageNativeSubstrate.JIMAGE_FindResource(jimageHandle,
+ moduleName, "9.0", className, sizeArray);
+ long size = sizeArray[0];
+ System.out.printf("reading: module: %s, path: %s, handle: %16x, " +
+ "location: %d, size: %d%n",
+ moduleName, className, jimageHandle, locationHandle, size);
+ if (moduleName.contains("NOSUCH") || className.contains("NOSUCH")) {
+ Assert.assertEquals(locationHandle, NOT_FOUND,
+ "location found for non-existing module: "
+ + moduleName
+ + ", or class: " + className);
+ return; // no more to test for non-existing class
+ } else {
+ Assert.assertTrue(locationHandle != NOT_FOUND, "location not found: " + className);
+ Assert.assertTrue(size > 0, "size of should be > 0: " + className);
+ }
+
+ // positive: read whole class
+ ByteBuffer buffer = ByteBuffer.allocate((int)size);
+ long actual = ImageNativeSubstrate.JIMAGE_GetResource(jimageHandle,
+ locationHandle, buffer.array(), size);
+ Assert.assertEquals(actual, size, "bytes read not equal bytes requested");
+
+ if (className.endsWith(".class")) {
+ int m = buffer.getInt();
+ Assert.assertEquals(m, classMagic, "Classfile has bad magic number");
+ }
+
+ // Read less than the size of the artifact
+ buffer.rewind();
+ Arrays.fill(buffer.array(), (byte)0xc0);
+ long sizeExpected = size - 10;
+ actual = ImageNativeSubstrate.JIMAGE_GetResource(jimageHandle,
+ locationHandle, buffer.array(), sizeExpected);
+ Assert.assertEquals(actual, sizeExpected, "bytes read not equal bytes requested");
+
+ if (className.endsWith(".class")) {
+ int m1 = buffer.getInt();
+ Assert.assertEquals(m1, classMagic, "Read operation succeeded but has bad magic number");
+ }
+
+ ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
+ }
+
+ /**
+ * For all the resource names, check the name and approximate count.
+ *
+ * @throws IOException thrown if an error occurs
+ */
+ @Test
+ static void test2_ImageResources() throws IOException {
+ if (!(new File(imageFile)).exists()) {
+ System.out.printf("Test skipped; no jimage file");
+ return;
+ }
+
+ long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
+ Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
+
+ String[] names = new String[4096];
+ int max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle,
+ names);
+
+ // Repeat with count available
+ names = new String[max + 1];
+ int count = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle,
+ names);
+ System.out.printf(" count: %d, a class: %s\n", count, names[0]);
+ Assert.assertTrue(max > 31000,
+ "missing entries, should be more than 31000, reported: " + count);
+ Assert.assertTrue(count == max,
+ "unexpected count of entries, count: " + count
+ + ", max: " + max);
+ for (int i = 0; i < count; i++) {
+ checkFullName(names[i]);
+ }
+
+ ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
+ }
+
+ /**
+ * Tests that a package exists and correctly mapped to the module.
+ *
+ * @param moduleName the module name
+ * @param packageName the package name
+ * @throws IOException thrown if an error occurs
+ */
+ @Test(dataProvider="packages")
+ static void test3_PackageToModule(String moduleName, String packageName) throws IOException {
+ if (!(new File(imageFile)).exists()) {
+ System.out.printf("Test skipped; no jimage file");
+ return;
+ }
+
+ long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
+ Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
+
+ String result = ImageNativeSubstrate.JIMAGE_PackageToModule(jimageHandle, packageName);
+ System.out.printf(" package: %s, module: %s%n", packageName, result);
+ Assert.assertEquals(result, moduleName, "wrong module for package: " + packageName);
+
+ ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
+ }
+
+
+ static void checkFullName(String path) {
+ int next = 0;
+ String m = null;
+ String p = null;
+ String b = null;
+ String e = null;
+ if (path.startsWith("/")) {
+ next = path.indexOf('/', 1);
+ m = path.substring(1, next);
+ next = next + 1;
+ }
+ int lastSlash = path.lastIndexOf('/');
+ if (lastSlash > next) {
+ // has a parent
+ p = path.substring(next, lastSlash);
+ next = lastSlash + 1;
+ }
+ int period = path.indexOf('.', next);
+ if (period > next) {
+ b = path.substring(next, period);
+ e = path.substring(period + 1);
+ } else {
+ b = path.substring(next);
+ }
+ Assert.assertNotNull(m, "module must be non-empty");
+ Assert.assertNotNull(b, "base name must be non-empty");
+ }
+
+ /**
+ * Verify that all of the resource names from BasicImageReader
+ * match those returned from the native JIMAGE_Resources iterator.
+ * Names that start with /modules, /packages, and bootmodules.jdata
+ * must appear in the names from JIMAGE_Resource iterator;
+ * from the BasicImageReader they are ignored.
+ */
+ @Test
+ static void test4_verifyNames() {
+ if (!(new File(imageFile)).exists()) {
+ System.out.printf("Test skipped; no jimage file");
+ return;
+ }
+
+ try {
+ String[] names = BasicImageReader_Names();
+ //writeNames("/tmp/basic-names.txt", names); // debug
+
+ // Read all the names from the native JIMAGE API
+ String[] nativeNames = JIMAGE_Names();
+ //writeNames("/tmp/native-names.txt", nativeNames); // debug
+
+
+ int modCount = 0;
+ int pkgCount = 0;
+ int otherCount = 0;
+ for (String n : nativeNames) {
+ if (n.startsWith("/modules/")) {
+ modCount++;
+ } else if (n.startsWith("/packages/")) {
+ pkgCount++;
+ } else {
+ otherCount++;
+ }
+ }
+ System.out.printf("native name count: %d, modCount: %d, pkgCount: %d, otherCount: %d%n",
+ names.length, modCount, pkgCount, otherCount);
+
+ Assert.assertEquals(modCount, 0, "JIMAGE_ResourceIterator should not return any '/modules' paths");
+ Assert.assertEquals(pkgCount, 0, "JIMAGE_ResourceIterator should not return any '/packages' paths");
+
+ // Sort and merge the two arrays. Every name should appear exactly twice.
+ Arrays.sort(names);
+ Arrays.sort(nativeNames);
+ String[] combined = Arrays.copyOf(names, nativeNames.length + names.length);
+ System.arraycopy(nativeNames,0, combined, names.length, nativeNames.length);
+ Arrays.sort(combined);
+ int missing = 0;
+ for (int i = 0; i < combined.length; i++) {
+ String s = combined[i];
+ if (isMetaName(s)) {
+ // Ignore /modules and /packages in BasicImageReader names
+ continue;
+ }
+
+ if (i < combined.length - 1 && s.equals(combined[i + 1])) {
+ i++; // string appears in both java and native
+ continue;
+ }
+
+ missing++;
+ int ndx = Arrays.binarySearch(names, s);
+ String which = (ndx >= 0) ? "java BasicImageReader" : "native JIMAGE_Resources";
+ System.out.printf("Missing Resource: %s found only via %s%n", s, which);
+ }
+ Assert.assertEquals(missing, 0, "Resources missing");
+
+ } catch (IOException ioe) {
+ Assert.fail("I/O exception", ioe);
+ }
+ }
+
+ /**
+ * Return true if the name is one of the meta-data names
+ * @param name a name
+ * @return return true if starts with either /packages or /modules
+ */
+ static boolean isMetaName(String name) {
+ return name.startsWith("/modules")
+ || name.startsWith("/packages")
+ || name.equals("bootmodules.jdata");
+ }
+
+ /**
+ * Return all of the names from BasicImageReader.
+ * @return the names returned from BasicImageReader
+ */
+ static String[] BasicImageReader_Names() throws IOException {
+ String[] names = null;
+ try (BasicImageReader reader = BasicImageReader.open(imageFile)) {
+ names = reader.getEntryNames();
+ } catch (IOException ioe) {
+ Assert.fail("I/O exception", ioe);
+ }
+ return names;
+ }
+
+ /**
+ * Returns an array of all of the names returned from JIMAGE_Resources
+ */
+ static String[] JIMAGE_Names() throws IOException {
+
+ long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile);
+ Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle);
+
+ String[] names = new String[50000];
+ int max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, names);
+
+ if (max > names.length) {
+ // Not all names fit, repeat with correct size
+ names = new String[max];
+ max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, names);
+ } else {
+ names = Arrays.copyOf(names, max);
+ }
+
+ ImageNativeSubstrate.JIMAGE_Close(jimageHandle);
+ return names;
+ }
+
+ // Write an array of names to a file for debugging
+ static void writeNames(String fname, String[] names) throws IOException {
+ try (FileWriter wr = new FileWriter(new File(fname))) {
+ for (String s : names) {
+ wr.write(s);
+ wr.write("\n");
+ }
+
+ }
+ System.out.printf(" %s: %d names%n", fname, names.length);
+ }
+
+ // main method to run standalone from jtreg
+
+ @Test(enabled=false)
+ @Parameters({"x"})
+ @SuppressWarnings("raw_types")
+ public static void main(@Optional String[] args) {
+ Class<?>[] testclass = { JImageReadTest.class};
+ TestNG testng = new TestNG();
+ testng.setTestClasses(testclass);
+ testng.run();
+ }
+
+}