OpenJDK / jdk / jdk
changeset 58891:1fa1ec0e7048
8242959: Optimize ZipFile.getEntry by folding lookups for name and name+'/'
Reviewed-by: lancea, redestad
Contributed-by: eirbjo@gmail.com
author | redestad |
---|---|
date | Sat, 18 Apr 2020 20:19:45 +0200 |
parents | 8fa94c849901 |
children | b465259f14be |
files | src/java.base/share/classes/java/util/zip/ZipFile.java |
diffstat | 1 files changed, 37 insertions(+), 50 deletions(-) [+] |
line wrap: on
line diff
--- a/src/java.base/share/classes/java/util/zip/ZipFile.java Sat Apr 18 19:45:45 2020 +0200 +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java Sat Apr 18 20:19:45 2020 +0200 @@ -1289,6 +1289,12 @@ } private static final int hashN(byte[] a, int off, int len) { + // Performance optimization: getEntryPos assumes that the hash + // of a name remains unchanged when appending a trailing '/'. + if (len > 0 && a[off + len - 1] == '/') { + len--; + } + int h = 1; while (len-- > 0) { h = 31 * h + a[off++]; @@ -1296,10 +1302,6 @@ return h; } - private static final int hashAppend(int hash, byte b) { - return hash * 31 + b; - } - private static class End { int centot; // 4 bytes long cenlen; // 4 bytes @@ -1537,56 +1539,41 @@ } int hsh = hashN(name, 0, name.length); int idx = table[(hsh & 0x7fffffff) % tablelen]; - boolean appendSlash = false; - /* - * This while loop is an optimization where a double lookup - * for name and name+/ is being performed. The name byte - * array will be updated with an added slash only if the first - * table lookup fails and there is a matching hash value for - * name+/. - */ - while (true) { - /* - * Search down the target hash chain for a entry whose - * 32 bit hash matches the hashed name. - */ - while (idx != ZIP_ENDCHAIN) { - if (getEntryHash(idx) == hsh) { - if (appendSlash) { - name = Arrays.copyOf(name, name.length + 1); - name[name.length - 1] = '/'; - appendSlash = false; + + // Search down the target hash chain for a entry whose + // 32 bit hash matches the hashed name. + while (idx != ZIP_ENDCHAIN) { + if (getEntryHash(idx) == hsh) { + // The CEN name must match the specfied one + int pos = getEntryPos(idx); + final int nlen = CENNAM(cen, pos); + final int nstart = pos + CENHDR; + + // If addSlash is true, we're testing for name+/ in + // addition to name, unless name is the empty string + // or already ends with a slash + if (name.length == nlen || + (addSlash && + name.length > 0 && + name.length + 1 == nlen && + cen[nstart + nlen - 1] == '/' && + name[name.length - 1] != '/')) { + boolean matched = true; + int nameoff = pos + CENHDR; + for (int i = 0; i < name.length; i++) { + if (name[i] != cen[nameoff++]) { + matched = false; + break; + } } - // The CEN name must match the specfied one - int pos = getEntryPos(idx); - if (name.length == CENNAM(cen, pos)) { - boolean matched = true; - int nameoff = pos + CENHDR; - for (int i = 0; i < name.length; i++) { - if (name[i] != cen[nameoff++]) { - matched = false; - break; - } - } - if (matched) { - return pos; - } - } + if (matched) { + return pos; + } } - idx = getEntryNext(idx); } - /* If not addSlash, or slash is already there, we are done */ - if (!addSlash || name.length == 0 || name[name.length - 1] == '/') { - return -1; - } - // Add a slash to the hash code - hsh = hashAppend(hsh, (byte)'/'); - // If we find a match on the new hash code, we need to append a - // slash when comparing - appendSlash = true; - idx = table[(hsh & 0x7fffffff) % tablelen]; - addSlash = false; + idx = getEntryNext(idx); } + return -1; } /**