--- old/src/java.base/share/classes/jdk/internal/jimage/BasicImageWriter.java 2015-06-23 14:28:52.000000000 +0200 +++ new/src/java.base/share/classes/jdk/internal/jimage/BasicImageWriter.java 2015-06-23 14:28:52.000000000 +0200 @@ -25,67 +25,30 @@ package jdk.internal.jimage; -import java.io.PrintStream; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; public final class BasicImageWriter { + + public static final String IMAGE_EXT = ".jimage"; + public static final String BOOT_NAME = "bootmodules"; + public static final String BOOT_IMAGE_NAME = BOOT_NAME + IMAGE_EXT; + private final static int RETRY_LIMIT = 1000; private ByteOrder byteOrder; - private ImageStrings strings; - private int count; + private ImageStringsWriter strings; + private int length; private int[] redirect; - private ImageLocation[] locations; - private List input; + private ImageLocationWriter[] locations; + private List input; private ImageStream headerStream; private ImageStream redirectStream; private ImageStream locationOffsetStream; private ImageStream locationStream; private ImageStream allIndexStream; - static class ImageBucket implements Comparable { - final List list; - - ImageBucket() { - this.list = new ArrayList<>(); - } - - void add(ImageLocation location) { - list.add(location); - } - - int getSize() { - return list.size(); - } - - List getList() { - return list; - } - - ImageLocation getFirst() { - assert !list.isEmpty() : "bucket should never be empty"; - return list.get(0); - } - - @Override - public int hashCode() { - return getFirst().hashCode(); - } - - @Override - public boolean equals(Object obj) { - return this == obj; - } - - @Override - public int compareTo(ImageBucket o) { - return o.getSize() - getSize(); - } - } - public BasicImageWriter() { this(ByteOrder.nativeOrder()); } @@ -93,7 +56,7 @@ public BasicImageWriter(ByteOrder byteOrder) { this.byteOrder = byteOrder; this.input = new ArrayList<>(); - this.strings = new ImageStrings(); + this.strings = new ImageStringsWriter(); this.headerStream = new ImageStream(byteOrder); this.redirectStream = new ImageStream(byteOrder); this.locationOffsetStream = new ImageStream(byteOrder); @@ -101,6 +64,10 @@ this.allIndexStream = new ImageStream(byteOrder); } + public ByteOrder getByteOrder() { + return byteOrder; + } + public int addString(String string) { return addString(new UTF8String(string)); } @@ -109,104 +76,48 @@ return strings.add(string); } - public void addLocation(String fullname, long contentOffset, long compressedSize, long uncompressedSize) { - ImageLocation location = ImageLocation.newLocation(new UTF8String(fullname), strings, contentOffset, compressedSize, uncompressedSize); - input.add(location); - count++; + public String getString(int offset) { + UTF8String utf8 = strings.get(offset); + return utf8 != null? utf8.toString() : null; } - private void generatePerfectHash() { - redo: - while(true) { - redirect = new int[count]; - locations = new ImageLocation[count]; - - ImageBucket[] sorted = createBuckets(); - - int free = 0; - - for (ImageBucket bucket : sorted) { - if (bucket.getSize() != 1) { - if (!packCollidedEntries(bucket, count)) { - count = (count + 1) | 1; - - continue redo; - } - } else { - for ( ; free < count && locations[free] != null; free++) {} - assert free < count : "no free slots"; - locations[free] = bucket.getFirst(); - redirect[bucket.hashCode() % count] = -1 - free; - free++; - } - } - - break; - } + public void addLocation(String fullname, long contentOffset, + long compressedSize, long uncompressedSize) { + ImageLocationWriter location = + ImageLocationWriter.newLocation(new UTF8String(fullname), strings, + contentOffset, compressedSize, uncompressedSize); + input.add(location); + length++; } - private ImageBucket[] createBuckets() { - ImageBucket[] buckets = new ImageBucket[count]; - - input.stream().forEach((location) -> { - int index = location.hashCode() % count; - ImageBucket bucket = buckets[index]; - - if (bucket == null) { - buckets[index] = bucket = new ImageBucket(); - } - - bucket.add(location); - }); - - ImageBucket[] sorted = Arrays.asList(buckets).stream() - .filter((bucket) -> (bucket != null)) - .sorted() - .toArray(ImageBucket[]::new); - - return sorted; + ImageLocationWriter[] getLocations() { + return locations; } - private boolean packCollidedEntries(ImageBucket bucket, int count) { - List undo = new ArrayList<>(); - int base = UTF8String.HASH_MULTIPLIER + 1; - - int retry = 0; - - redo: - while (true) { - for (ImageLocation location : bucket.getList()) { - int index = location.hashCode(base) % count; - - if (locations[index] != null) { - undo.stream().forEach((i) -> { - locations[i] = null; - }); - - undo.clear(); - base++; - - if (base == 0) { - base = 1; - } + int getLocationsCount() { + return input.size(); + } - if (++retry > RETRY_LIMIT) { - return false; - } + private void generatePerfectHash() { + PerfectHashBuilder builder = + new PerfectHashBuilder<>( + new PerfectHashBuilder.Entry().getClass(), + new PerfectHashBuilder.Bucket().getClass()); - continue redo; - } + input.forEach((location) -> { + builder.put(location.getFullName(), location); + }); - locations[index] = location; - undo.add(index); - } + builder.generate(); - redirect[bucket.hashCode() % count] = base; + length = builder.getCount(); + redirect = builder.getRedirect(); + PerfectHashBuilder.Entry[] order = builder.getOrder(); + locations = new ImageLocationWriter[length]; - break; + for (int i = 0; i < length; i++) { + locations[i] = order[i].getValue(); } - - return true; } private void prepareStringBytes() { @@ -214,17 +125,17 @@ } private void prepareRedirectBytes() { - for (int i = 0; i < count; i++) { + for (int i = 0; i < length; i++) { redirectStream.putInt(redirect[i]); } } private void prepareLocationBytes() { // Reserve location offset zero for empty locations - locationStream.put(ImageLocation.ATTRIBUTE_END << 3); + locationStream.put(ImageLocationWriter.ATTRIBUTE_END << 3); - for (int i = 0; i < count; i++) { - ImageLocation location = locations[i]; + for (int i = 0; i < length; i++) { + ImageLocationWriter location = locations[i]; if (location != null) { location.writeTo(locationStream); @@ -235,14 +146,16 @@ } private void prepareOffsetBytes() { - for (int i = 0; i < count; i++) { - ImageLocation location = locations[i]; - locationOffsetStream.putInt(location != null ? location.getLocationOffset() : 0); + for (int i = 0; i < length; i++) { + ImageLocationWriter location = locations[i]; + int offset = location != null ? location.getLocationOffset() : 0; + locationOffsetStream.putInt(offset); } } private void prepareHeaderBytes() { - ImageHeader header = new ImageHeader(count, locationStream.getSize(), strings.getSize()); + ImageHeader header = new ImageHeader(input.size(), length, + locationStream.getSize(), strings.getSize()); header.writeTo(headerStream); } @@ -268,33 +181,15 @@ return allIndexStream.toArray(); } - ImageLocation find(UTF8String key) { - int index = key.hashCode() % count; - index = redirect[index]; + ImageLocationWriter find(UTF8String key) { + int index = redirect[key.hashCode() % length]; if (index < 0) { index = -index - 1; - ImageLocation location = locations[index]; - - return location; } else { - index = key.hashCode(index) % count; - ImageLocation location = locations[index]; - - return location; + index = key.hashCode(index) % length; } - } - public void statistics() { - getBytes(); - PrintStream out = System.out; - out.println("Count: " + count); - out.println("Header bytes size: " + headerStream.getSize()); - out.println("Redirect bytes size: " + redirectStream.getSize()); - out.println("Offset bytes size: " + locationOffsetStream.getSize()); - out.println("Location bytes size: " + locationStream.getSize()); - out.println("String count: " + strings.getCount()); - out.println("String bytes size: " + strings.getSize()); - out.println("Total bytes size: " + allIndexStream.getSize()); + return locations[index]; } }