--- old/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java 2017-02-27 13:57:10.806465570 +0100 +++ new/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java 2017-02-27 13:57:10.610464598 +0100 @@ -249,11 +249,31 @@ return stringsReader; } - public ImageLocation findLocation(String mn, String rn) { - Objects.requireNonNull(mn); - Objects.requireNonNull(rn); + public synchronized ImageLocation findLocation(String module, String name) { + Objects.requireNonNull(module); + Objects.requireNonNull(name); + // Details of the algorithm used here can be found in + // jdk.tools.jlink.internal.PerfectHashBuilder. + int count = header.getTableLength(); + int index = redirect.get(ImageStringsReader.hashCode(module, name) % count); - return findLocation("/" + mn + "/" + rn); + if (index < 0) { + // index is twos complement of location attributes index. + index = -index - 1; + } else if (index > 0) { + // index is hash seed needed to compute location attributes index. + index = ImageStringsReader.hashCode(module, name, index) % count; + } else { + // No entry. + return null; + } + + long[] attributes = getAttributes(offsets.get(index)); + + if (!ImageLocation.verify(module, name, attributes, stringsReader)) { + return null; + } + return new ImageLocation(attributes, stringsReader); } public synchronized ImageLocation findLocation(String name) { --- old/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java 2017-02-27 13:57:11.510469061 +0100 +++ new/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java 2017-02-27 13:57:11.318468109 +0100 @@ -147,7 +147,27 @@ } } - int parentOffset = (int)attributes[ATTRIBUTE_PARENT]; + return verifyName(name, index, length, attributes, strings); + } + + static boolean verify(String module, String name, + final long[] attributes, final ImageStrings strings) { + Objects.requireNonNull(module); + Objects.requireNonNull(name); + int moduleOffset = (int)attributes[ATTRIBUTE_MODULE]; + if (moduleOffset != 0) { + if (!module.equals(strings.get(moduleOffset))) { + return false; + } + } + + return verifyName(name, 0, name.length(), attributes, strings); + } + + private static boolean verifyName(String name, int index, final int length, + final long[] attributes, final ImageStrings strings) { + + int parentOffset = (int) attributes[ATTRIBUTE_PARENT]; if (parentOffset != 0) { String parent = strings.get(parentOffset); final int parentLen = parent.length(); @@ -159,15 +179,13 @@ return false; } } - - String base = strings.get((int)attributes[ATTRIBUTE_BASE]); + String base = strings.get((int) attributes[ATTRIBUTE_BASE]); final int baseLen = base.length(); if (!name.regionMatches(index, base, 0, baseLen)) { return false; } index += baseLen; - - int extOffset = (int)attributes[ATTRIBUTE_EXTENSION]; + int extOffset = (int) attributes[ATTRIBUTE_EXTENSION]; if (extOffset != 0) { String extension = strings.get(extOffset); int extLen = extension.length(); --- old/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java 2017-02-27 13:57:12.270472829 +0100 +++ new/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java 2017-02-27 13:57:12.030471639 +0100 @@ -38,6 +38,8 @@ */ public class ImageStringsReader implements ImageStrings { public static final int HASH_MULTIPLIER = 0x01000193; + public static final int POSITIVE_MASK = 0x7FFFFFFF; + private final BasicImageReader reader; ImageStringsReader(BasicImageReader reader) { @@ -54,40 +56,27 @@ throw new InternalError("Can not add strings at runtime"); } - private static int hashCode(byte[] bytes, int offset, int count, int seed) { - Objects.requireNonNull(bytes); - - if (offset < 0 || count < 0 || offset > bytes.length - count) { - throw new IndexOutOfBoundsException("offset=" + offset + ", count=" + count); - } - - int limit = offset + count; - - if (limit < 0 || limit > bytes.length) { - throw new IndexOutOfBoundsException("limit=" + limit); - } - - for (int i = offset; i < limit; i++) { - seed = (seed * HASH_MULTIPLIER) ^ (bytes[i] & 0xFF); - } - - return seed & 0x7FFFFFFF; + public static int hashCode(String string) { + return hashCode(string, HASH_MULTIPLIER); } - public static int hashCode(byte[] bytes, int seed) { - return hashCode(bytes, 0, bytes.length, seed); + public static int hashCode(String string, int seed) { + return unmaskedHashCode(string, seed) & POSITIVE_MASK; } - public static int hashCode(byte[] bytes) { - return hashCode(bytes, 0, bytes.length, HASH_MULTIPLIER); + public static int hashCode(String module, String string) { + return hashCode(module, string, HASH_MULTIPLIER); } - public static int hashCode(String string) { - return hashCode(string, HASH_MULTIPLIER); + public static int hashCode(String module, String string, int seed) { + seed = unmaskedHashCode("/", seed); + seed = unmaskedHashCode(module, seed); + seed = unmaskedHashCode("/", seed); + seed = unmaskedHashCode(string, seed); + return seed & POSITIVE_MASK; } - public static int hashCode(String string, int seed) { - + public static int unmaskedHashCode(String string, int seed) { int slen = string.length(); byte[] buffer = null; @@ -120,8 +109,7 @@ seed = (seed * HASH_MULTIPLIER) ^ (uch); } } - - return seed & 0x7FFFFFFF; + return seed; } static int charsFromMUTF8Length(byte[] bytes, int offset, int count) { @@ -265,6 +253,7 @@ static int mutf8FromStringLength(String s) { int length = 0; int slen = s.length(); + for (int i = 0; i < slen; i++) { char ch = s.charAt(i); int uch = ch & 0xFFFF; --- old/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageLocationWriter.java 2017-02-27 13:57:13.014476519 +0100 +++ new/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageLocationWriter.java 2017-02-27 13:57:12.762475269 +0100 @@ -108,24 +108,24 @@ int hash = seed; if (getModuleOffset() != 0) { - hash = ImageStringsReader.hashCode("/", hash); - hash = ImageStringsReader.hashCode(getModule(), hash); - hash = ImageStringsReader.hashCode("/", hash); + hash = ImageStringsReader.unmaskedHashCode("/", hash); + hash = ImageStringsReader.unmaskedHashCode(getModule(), hash); + hash = ImageStringsReader.unmaskedHashCode("/", hash); } if (getParentOffset() != 0) { - hash = ImageStringsReader.hashCode(getParent(), hash); - hash = ImageStringsReader.hashCode("/", hash); + hash = ImageStringsReader.unmaskedHashCode(getParent(), hash); + hash = ImageStringsReader.unmaskedHashCode("/", hash); } - hash = ImageStringsReader.hashCode(getBase(), hash); + hash = ImageStringsReader.unmaskedHashCode(getBase(), hash); if (getExtensionOffset() != 0) { - hash = ImageStringsReader.hashCode(".", hash); - hash = ImageStringsReader.hashCode(getExtension(), hash); + hash = ImageStringsReader.unmaskedHashCode(".", hash); + hash = ImageStringsReader.unmaskedHashCode(getExtension(), hash); } - return hash; + return hash & ImageStringsReader.POSITIVE_MASK; } @Override