This commit is contained in:
Lana Steuck 2017-03-03 01:45:06 +00:00
commit 87d92f70f4
6 changed files with 221 additions and 91 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2017, 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
@ -471,7 +471,7 @@ class Properties extends Hashtable<Object,Object> {
if (inStream != null) {
//The line below is equivalent to calling a
//ISO8859-1 decoder.
c = (char) (0xff & inByteBuf[inOff++]);
c = (char)(inByteBuf[inOff++] & 0xFF);
} else {
c = inCharBuf[inOff++];
}
@ -494,8 +494,25 @@ class Properties extends Hashtable<Object,Object> {
if (isNewLine) {
isNewLine = false;
if (c == '#' || c == '!') {
// Comment, quickly consume the rest of the line,
// resume on line-break and backslash.
if (inStream != null) {
while (inOff < inLimit) {
byte b = inByteBuf[inOff++];
if (b == '\n' || b == '\r' || b == '\\') {
c = (char)(b & 0xFF);
break;
}
}
} else {
while (inOff < inLimit) {
c = inCharBuf[inOff++];
if (c == '\n' || c == '\r' || c == '\\') {
break;
}
}
}
isCommentLine = true;
continue;
}
}

View File

@ -249,27 +249,20 @@ public class BasicImageReader implements AutoCloseable {
return stringsReader;
}
public ImageLocation findLocation(String mn, String rn) {
Objects.requireNonNull(mn);
Objects.requireNonNull(rn);
return findLocation("/" + mn + "/" + rn);
}
public synchronized ImageLocation findLocation(String name) {
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.
byte[] bytes = ImageStringsReader.mutf8FromString(name);
int count = header.getTableLength();
int index = redirect.get(ImageStringsReader.hashCode(bytes) % count);
int index = redirect.get(ImageStringsReader.hashCode(module, name) % count);
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(bytes, index) % count;
index = ImageStringsReader.hashCode(module, name, index) % count;
} else {
// No entry.
return null;
@ -277,13 +270,36 @@ public class BasicImageReader implements AutoCloseable {
long[] attributes = getAttributes(offsets.get(index));
ImageLocation imageLocation = new ImageLocation(attributes, stringsReader);
if (!ImageLocation.verify(module, name, attributes, stringsReader)) {
return null;
}
return new ImageLocation(attributes, stringsReader);
}
if (!imageLocation.verify(name)) {
public synchronized ImageLocation findLocation(String name) {
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(name) % count);
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(name, index) % count;
} else {
// No entry.
return null;
}
return imageLocation;
long[] attributes = getAttributes(offsets.get(index));
if (!ImageLocation.verify(name, attributes, stringsReader)) {
return null;
}
return new ImageLocation(attributes, stringsReader);
}
public String[] getEntryNames() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2017, 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
@ -59,14 +59,6 @@ public class ImageLocation {
return strings;
}
private static int attributeLength(int data) {
return (data & 0x7) + 1;
}
private static int attributeKind(int data) {
return data >>> 3;
}
static long[] decompress(ByteBuffer bytes) {
Objects.requireNonNull(bytes);
long[] attributes = new long[ATTRIBUTE_COUNT];
@ -74,7 +66,7 @@ public class ImageLocation {
if (bytes != null) {
while (bytes.hasRemaining()) {
int data = bytes.get() & 0xFF;
int kind = attributeKind(data);
int kind = data >>> 3;
if (kind == ATTRIBUTE_END) {
break;
@ -85,7 +77,7 @@ public class ImageLocation {
"Invalid jimage attribute kind: " + kind);
}
int length = attributeLength(data);
int length = (data & 0x7) + 1;
long value = 0;
for (int j = 0; j < length; j++) {
@ -128,9 +120,82 @@ public class ImageLocation {
}
public boolean verify(String name) {
Objects.requireNonNull(name);
return verify(name, attributes, strings);
}
return name.equals(getFullName());
/**
* A simpler verification would be {@code name.equals(getFullName())}, but
* by not creating the full name and enabling early returns we allocate
* fewer objects. Could possibly be made allocation free by extending
* ImageStrings to test if strings at an offset match the name region.
*/
static boolean verify(String name, long[] attributes, ImageStrings strings) {
Objects.requireNonNull(name);
final int length = name.length();
int index = 0;
int moduleOffset = (int)attributes[ATTRIBUTE_MODULE];
if (moduleOffset != 0) {
String module = strings.get(moduleOffset);
final int moduleLen = module.length();
index = moduleLen + 1;
if (length <= index
|| name.charAt(0) != '/'
|| !name.regionMatches(1, module, 0, moduleLen)
|| name.charAt(index++) != '/') {
return false;
}
}
return verifyName(name, index, length, attributes, strings);
}
static boolean verify(String module, String name, long[] attributes,
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, int length,
long[] attributes, ImageStrings strings) {
int parentOffset = (int) attributes[ATTRIBUTE_PARENT];
if (parentOffset != 0) {
String parent = strings.get(parentOffset);
final int parentLen = parent.length();
if (!name.regionMatches(index, parent, 0, parentLen)) {
return false;
}
index += parentLen;
if (length <= index || name.charAt(index++) != '/') {
return false;
}
}
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];
if (extOffset != 0) {
String extension = strings.get(extOffset);
int extLen = extension.length();
if (length <= index
|| name.charAt(index++) != '.'
|| !name.regionMatches(index, extension, 0, extLen)) {
return false;
}
index += extLen;
}
return length == index;
}
long getAttribute(int kind) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2017, 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
@ -38,6 +38,8 @@ import java.util.Objects;
*/
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,60 @@ public class ImageStringsReader implements ImageStrings {
throw new InternalError("Can not add strings at runtime");
}
private static int hashCode(byte[] bytes, int offset, int count, int seed) {
Objects.requireNonNull(bytes);
public static int hashCode(String s) {
return hashCode(s, HASH_MULTIPLIER);
}
if (offset < 0 || count < 0 || offset > bytes.length - count) {
throw new IndexOutOfBoundsException("offset=" + offset + ", count=" + count);
public static int hashCode(String s, int seed) {
return unmaskedHashCode(s, seed) & POSITIVE_MASK;
}
public static int hashCode(String module, String name) {
return hashCode(module, name, HASH_MULTIPLIER);
}
public static int hashCode(String module, String name, int seed) {
seed = unmaskedHashCode("/", seed);
seed = unmaskedHashCode(module, seed);
seed = unmaskedHashCode("/", seed);
seed = unmaskedHashCode(name, seed);
return seed & POSITIVE_MASK;
}
public static int unmaskedHashCode(String s, int seed) {
int slen = s.length();
byte[] buffer = null;
for (int i = 0; i < slen; i++) {
char ch = s.charAt(i);
int uch = ch & 0xFFFF;
if ((uch & ~0x7F) != 0) {
if (buffer == null) {
buffer = new byte[8];
}
int mask = ~0x3F;
int n = 0;
do {
buffer[n++] = (byte)(0x80 | (uch & 0x3F));
uch >>= 6;
mask >>= 1;
} while ((uch & mask) != 0);
buffer[n] = (byte)((mask << 1) | uch);
do {
seed = (seed * HASH_MULTIPLIER) ^ (buffer[n--] & 0xFF);
} while (0 <= n);
} else if (uch == 0) {
seed = (seed * HASH_MULTIPLIER) ^ (0xC0);
seed = (seed * HASH_MULTIPLIER) ^ (0x80);
} else {
seed = (seed * HASH_MULTIPLIER) ^ (uch);
}
}
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(byte[] bytes, int seed) {
return hashCode(bytes, 0, bytes.length, seed);
}
public static int hashCode(byte[] bytes) {
return hashCode(bytes, 0, bytes.length, HASH_MULTIPLIER);
}
public static int hashCode(String string, int seed) {
return hashCode(mutf8FromString(string), seed);
}
public static int hashCode(String string) {
return hashCode(mutf8FromString(string), HASH_MULTIPLIER);
return seed;
}
static int charsFromMUTF8Length(byte[] bytes, int offset, int count) {
@ -179,7 +201,7 @@ public class ImageStringsReader implements ImageStrings {
throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence");
}
static void charsFromByteBuffer(char chars[], ByteBuffer buffer) {
static void charsFromByteBuffer(char[] chars, ByteBuffer buffer) {
int j = 0;
while(buffer.hasRemaining()) {
@ -228,10 +250,12 @@ public class ImageStringsReader implements ImageStrings {
return new String(chars);
}
static int mutf8FromCharsLength(char chars[]) {
static int mutf8FromStringLength(String s) {
int length = 0;
int slen = s.length();
for (char ch : chars) {
for (int i = 0; i < slen; i++) {
char ch = s.charAt(i);
int uch = ch & 0xFFFF;
if ((uch & ~0x7F) != 0) {
@ -255,14 +279,19 @@ public class ImageStringsReader implements ImageStrings {
return length;
}
static void mutf8FromChars(byte[] bytes, int offset, char chars[]) {
static void mutf8FromString(byte[] bytes, int offset, String s) {
int j = offset;
byte[] buffer = new byte[8];
byte[] buffer = null;
int slen = s.length();
for (char ch : chars) {
for (int i = 0; i < slen; i++) {
char ch = s.charAt(i);
int uch = ch & 0xFFFF;
if ((uch & ~0x7F) != 0) {
if (buffer == null) {
buffer = new byte[8];
}
int mask = ~0x3F;
int n = 0;
@ -287,10 +316,9 @@ public class ImageStringsReader implements ImageStrings {
}
public static byte[] mutf8FromString(String string) {
char[] chars = string.toCharArray();
int length = mutf8FromCharsLength(chars);
int length = mutf8FromStringLength(string);
byte[] bytes = new byte[length];
mutf8FromChars(bytes, 0, chars);
mutf8FromString(bytes, 0, string);
return bytes;
}

View File

@ -237,6 +237,7 @@ public class Main {
if (!parseArgs(args)) {
return false;
}
File tmpFile = null;
try {
if (cflag || uflag) {
if (fname != null) {
@ -303,8 +304,8 @@ public class Main {
? "tmpjar"
: fname.substring(fname.indexOf(File.separatorChar) + 1);
File tmpfile = createTemporaryFile(tmpbase, ".jar");
try (OutputStream out = new FileOutputStream(tmpfile)) {
tmpFile = createTemporaryFile(tmpbase, ".jar");
try (OutputStream out = new FileOutputStream(tmpFile)) {
create(new BufferedOutputStream(out, 4096), manifest);
}
if (nflag) {
@ -313,16 +314,16 @@ public class Main {
Packer packer = Pack200.newPacker();
Map<String, String> p = packer.properties();
p.put(Packer.EFFORT, "1"); // Minimal effort to conserve CPU
try (JarFile jarFile = new JarFile(tmpfile.getCanonicalPath());
try (JarFile jarFile = new JarFile(tmpFile.getCanonicalPath());
OutputStream pack = new FileOutputStream(packFile))
{
packer.pack(jarFile, pack);
}
if (tmpfile.exists()) {
tmpfile.delete();
if (tmpFile.exists()) {
tmpFile.delete();
}
tmpfile = createTemporaryFile(tmpbase, ".jar");
try (OutputStream out = new FileOutputStream(tmpfile);
tmpFile = createTemporaryFile(tmpbase, ".jar");
try (OutputStream out = new FileOutputStream(tmpFile);
JarOutputStream jos = new JarOutputStream(out))
{
Unpacker unpacker = Pack200.newUnpacker();
@ -332,9 +333,9 @@ public class Main {
Files.deleteIfExists(packFile.toPath());
}
}
validateAndClose(tmpfile);
validateAndClose(tmpFile);
} else if (uflag) {
File inputFile = null, tmpFile = null;
File inputFile = null;
if (fname != null) {
inputFile = new File(fname);
tmpFile = createTempFileInSameDirectoryAs(inputFile);
@ -425,6 +426,9 @@ public class Main {
} catch (Throwable t) {
t.printStackTrace();
ok = false;
} finally {
if (tmpFile != null && tmpFile.exists())
tmpFile.delete();
}
out.flush();
err.flush();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2017, 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
@ -108,24 +108,24 @@ public final class ImageLocationWriter extends ImageLocation {
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