mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-19 02:24:40 +02:00
8260337: Optimize ImageReader lookup, used by Class.getResource
Reviewed-by: jlaskey, sundar
This commit is contained in:
parent
f0bd9db5c7
commit
2f893c2b83
8 changed files with 333 additions and 133 deletions
|
@ -3048,15 +3048,19 @@ public final class Class<T> implements java.io.Serializable,
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a package name prefix if the name is not absolute Remove leading "/"
|
||||
* Add a package name prefix if the name is not absolute. Remove leading "/"
|
||||
* if name is absolute
|
||||
*/
|
||||
private String resolveName(String name) {
|
||||
if (!name.startsWith("/")) {
|
||||
Class<?> c = isArray() ? elementType() : this;
|
||||
String baseName = c.getPackageName();
|
||||
String baseName = getPackageName();
|
||||
if (baseName != null && !baseName.isEmpty()) {
|
||||
name = baseName.replace('.', '/') + "/" + name;
|
||||
int len = baseName.length() + 1 + name.length();
|
||||
StringBuilder sb = new StringBuilder(len);
|
||||
name = sb.append(baseName.replace('.', '/'))
|
||||
.append('/')
|
||||
.append(name)
|
||||
.toString();
|
||||
}
|
||||
} else {
|
||||
name = name.substring(1);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2021, 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
|
||||
|
@ -249,59 +249,71 @@ public class BasicImageReader implements AutoCloseable {
|
|||
return stringsReader;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
public ImageLocation findLocation(String module, String name) {
|
||||
int index = getLocationIndex(module, name);
|
||||
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) {
|
||||
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);
|
||||
|
||||
public ImageLocation findLocation(String name) {
|
||||
int index = getLocationIndex(name);
|
||||
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;
|
||||
}
|
||||
|
||||
long[] attributes = getAttributes(offsets.get(index));
|
||||
|
||||
if (!ImageLocation.verify(name, attributes, stringsReader)) {
|
||||
return null;
|
||||
}
|
||||
return new ImageLocation(attributes, stringsReader);
|
||||
}
|
||||
|
||||
public boolean verifyLocation(String module, String name) {
|
||||
int index = getLocationIndex(module, name);
|
||||
if (index < 0) {
|
||||
return false;
|
||||
}
|
||||
int locationOffset = offsets.get(index);
|
||||
return ImageLocation.verify(module, name, locations, locationOffset, stringsReader);
|
||||
}
|
||||
|
||||
// Details of the algorithm used here can be found in
|
||||
// jdk.tools.jlink.internal.PerfectHashBuilder.
|
||||
public int getLocationIndex(String name) {
|
||||
int count = header.getTableLength();
|
||||
int index = redirect.get(ImageStringsReader.hashCode(name) % count);
|
||||
if (index < 0) {
|
||||
// index is twos complement of location attributes index.
|
||||
return -index - 1;
|
||||
} else if (index > 0) {
|
||||
// index is hash seed needed to compute location attributes index.
|
||||
return ImageStringsReader.hashCode(name, index) % count;
|
||||
} else {
|
||||
// No entry.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private int getLocationIndex(String module, String name) {
|
||||
int count = header.getTableLength();
|
||||
int index = redirect.get(ImageStringsReader.hashCode(module, name) % count);
|
||||
if (index < 0) {
|
||||
// index is twos complement of location attributes index.
|
||||
return -index - 1;
|
||||
} else if (index > 0) {
|
||||
// index is hash seed needed to compute location attributes index.
|
||||
return ImageStringsReader.hashCode(module, name, index) % count;
|
||||
} else {
|
||||
// No entry.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getEntryNames() {
|
||||
int[] attributeOffsets = new int[offsets.capacity()];
|
||||
offsets.get(attributeOffsets);
|
||||
|
@ -320,18 +332,21 @@ public class BasicImageReader implements AutoCloseable {
|
|||
if (offset < 0 || offset >= locations.limit()) {
|
||||
throw new IndexOutOfBoundsException("offset");
|
||||
}
|
||||
|
||||
ByteBuffer buffer = slice(locations, offset, locations.limit() - offset);
|
||||
return ImageLocation.decompress(buffer);
|
||||
return ImageLocation.decompress(locations, offset);
|
||||
}
|
||||
|
||||
public String getString(int offset) {
|
||||
if (offset < 0 || offset >= strings.limit()) {
|
||||
throw new IndexOutOfBoundsException("offset");
|
||||
}
|
||||
return ImageStringsReader.stringFromByteBuffer(strings, offset);
|
||||
}
|
||||
|
||||
ByteBuffer buffer = slice(strings, offset, strings.limit() - offset);
|
||||
return ImageStringsReader.stringFromByteBuffer(buffer);
|
||||
public int match(int offset, String string, int stringOffset) {
|
||||
if (offset < 0 || offset >= strings.limit()) {
|
||||
throw new IndexOutOfBoundsException("offset");
|
||||
}
|
||||
return ImageStringsReader.stringFromByteBufferMatches(strings, offset, string, stringOffset);
|
||||
}
|
||||
|
||||
private byte[] getBufferBytes(ByteBuffer buffer) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2021, 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,41 +59,26 @@ public class ImageLocation {
|
|||
return strings;
|
||||
}
|
||||
|
||||
static long[] decompress(ByteBuffer bytes) {
|
||||
static long[] decompress(ByteBuffer bytes, int offset) {
|
||||
Objects.requireNonNull(bytes);
|
||||
long[] attributes = new long[ATTRIBUTE_COUNT];
|
||||
|
||||
if (bytes != null) {
|
||||
while (bytes.hasRemaining()) {
|
||||
int data = bytes.get() & 0xFF;
|
||||
int kind = data >>> 3;
|
||||
|
||||
if (kind == ATTRIBUTE_END) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
|
||||
throw new InternalError(
|
||||
"Invalid jimage attribute kind: " + kind);
|
||||
}
|
||||
|
||||
int length = (data & 0x7) + 1;
|
||||
long value = 0;
|
||||
|
||||
for (int j = 0; j < length; j++) {
|
||||
value <<= 8;
|
||||
|
||||
if (!bytes.hasRemaining()) {
|
||||
throw new InternalError("Missing jimage attribute data");
|
||||
}
|
||||
|
||||
value |= bytes.get() & 0xFF;
|
||||
}
|
||||
|
||||
attributes[kind] = value;
|
||||
int limit = bytes.limit();
|
||||
while (offset < limit) {
|
||||
int data = bytes.get(offset++) & 0xFF;
|
||||
if (data <= 0x7) { // ATTRIBUTE_END
|
||||
break;
|
||||
}
|
||||
int kind = data >>> 3;
|
||||
if (ATTRIBUTE_COUNT <= kind) {
|
||||
throw new InternalError(
|
||||
"Invalid jimage attribute kind: " + kind);
|
||||
}
|
||||
}
|
||||
|
||||
int length = (data & 0x7) + 1;
|
||||
attributes[kind] = readValue(length, bytes, offset, limit);
|
||||
offset += length;
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
|
@ -126,51 +111,105 @@ public class ImageLocation {
|
|||
/**
|
||||
* 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.
|
||||
* fewer objects.
|
||||
*/
|
||||
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();
|
||||
if (moduleOffset != 0 && length >= 1) {
|
||||
int moduleLen = strings.match(moduleOffset, name, 1);
|
||||
index = moduleLen + 1;
|
||||
if (length <= index
|
||||
if (moduleLen < 0
|
||||
|| length <= index
|
||||
|| name.charAt(0) != '/'
|
||||
|| !name.regionMatches(1, module, 0, moduleLen)
|
||||
|| name.charAt(index++) != '/') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return verifyName(null, name, index, length, 0,
|
||||
(int) attributes[ATTRIBUTE_PARENT],
|
||||
(int) attributes[ATTRIBUTE_BASE],
|
||||
(int) attributes[ATTRIBUTE_EXTENSION],
|
||||
strings);
|
||||
}
|
||||
|
||||
return verifyName(name, index, length, attributes, strings);
|
||||
static boolean verify(String module, String name, ByteBuffer locations,
|
||||
int locationOffset, ImageStrings strings) {
|
||||
int moduleOffset = 0;
|
||||
int parentOffset = 0;
|
||||
int baseOffset = 0;
|
||||
int extOffset = 0;
|
||||
|
||||
int limit = locations.limit();
|
||||
while (locationOffset < limit) {
|
||||
int data = locations.get(locationOffset++) & 0xFF;
|
||||
if (data <= 0x7) { // ATTRIBUTE_END
|
||||
break;
|
||||
}
|
||||
int kind = data >>> 3;
|
||||
if (ATTRIBUTE_COUNT <= kind) {
|
||||
throw new InternalError(
|
||||
"Invalid jimage attribute kind: " + kind);
|
||||
}
|
||||
|
||||
int length = (data & 0x7) + 1;
|
||||
switch (kind) {
|
||||
case ATTRIBUTE_MODULE:
|
||||
moduleOffset = (int) readValue(length, locations, locationOffset, limit);
|
||||
break;
|
||||
case ATTRIBUTE_BASE:
|
||||
baseOffset = (int) readValue(length, locations, locationOffset, limit);
|
||||
break;
|
||||
case ATTRIBUTE_PARENT:
|
||||
parentOffset = (int) readValue(length, locations, locationOffset, limit);
|
||||
break;
|
||||
case ATTRIBUTE_EXTENSION:
|
||||
extOffset = (int) readValue(length, locations, locationOffset, limit);
|
||||
break;
|
||||
}
|
||||
locationOffset += length;
|
||||
}
|
||||
return verifyName(module, name, 0, name.length(),
|
||||
moduleOffset, parentOffset, baseOffset, extOffset, strings);
|
||||
}
|
||||
|
||||
private static long readValue(int length, ByteBuffer buffer, int offset, int limit) {
|
||||
long value = 0;
|
||||
for (int j = 0; j < length; j++) {
|
||||
value <<= 8;
|
||||
if (offset >= limit) {
|
||||
throw new InternalError("Missing jimage attribute data");
|
||||
}
|
||||
value |= buffer.get(offset++) & 0xFF;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static boolean verify(String module, String name, long[] attributes,
|
||||
ImageStrings strings) {
|
||||
Objects.requireNonNull(module);
|
||||
Objects.requireNonNull(name);
|
||||
int moduleOffset = (int)attributes[ATTRIBUTE_MODULE];
|
||||
return verifyName(module, name, 0, name.length(),
|
||||
(int) attributes[ATTRIBUTE_MODULE],
|
||||
(int) attributes[ATTRIBUTE_PARENT],
|
||||
(int) attributes[ATTRIBUTE_BASE],
|
||||
(int) attributes[ATTRIBUTE_EXTENSION],
|
||||
strings);
|
||||
}
|
||||
|
||||
private static boolean verifyName(String module, String name, int index, int length,
|
||||
int moduleOffset, int parentOffset, int baseOffset, int extOffset, ImageStrings strings) {
|
||||
|
||||
if (moduleOffset != 0) {
|
||||
if (!module.equals(strings.get(moduleOffset))) {
|
||||
if (strings.match(moduleOffset, module, 0) != module.length()) {
|
||||
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)) {
|
||||
int parentLen = strings.match(parentOffset, name, index);
|
||||
if (parentLen < 0) {
|
||||
return false;
|
||||
}
|
||||
index += parentLen;
|
||||
|
@ -178,19 +217,19 @@ public class ImageLocation {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
String base = strings.get((int) attributes[ATTRIBUTE_BASE]);
|
||||
final int baseLen = base.length();
|
||||
if (!name.regionMatches(index, base, 0, baseLen)) {
|
||||
int baseLen = strings.match(baseOffset, name, index);
|
||||
if (baseLen < 0) {
|
||||
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)) {
|
||||
|| name.charAt(index++) != '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
int extLen = strings.match(extOffset, name, index);
|
||||
if (extLen < 0) {
|
||||
return false;
|
||||
}
|
||||
index += extLen;
|
||||
|
@ -203,7 +242,6 @@ public class ImageLocation {
|
|||
throw new InternalError(
|
||||
"Invalid jimage attribute kind: " + kind);
|
||||
}
|
||||
|
||||
return attributes[kind];
|
||||
}
|
||||
|
||||
|
@ -212,7 +250,6 @@ public class ImageLocation {
|
|||
throw new InternalError(
|
||||
"Invalid jimage attribute kind: " + kind);
|
||||
}
|
||||
|
||||
return getStrings().get((int)attributes[kind]);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2021, 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
|
||||
|
@ -148,6 +148,11 @@ public final class ImageReader implements AutoCloseable {
|
|||
return reader.findLocation(mn, rn);
|
||||
}
|
||||
|
||||
public boolean verifyLocation(String mn, String rn) {
|
||||
requireOpen();
|
||||
return reader.verifyLocation(mn, rn);
|
||||
}
|
||||
|
||||
public ImageLocation findLocation(String name) {
|
||||
requireOpen();
|
||||
return reader.findLocation(name);
|
||||
|
@ -740,7 +745,7 @@ public final class ImageReader implements AutoCloseable {
|
|||
|
||||
public void walk(Consumer<? super Node> consumer) {
|
||||
consumer.accept(this);
|
||||
for ( Node child : children ) {
|
||||
for (Node child : children) {
|
||||
if (child.isDirectory()) {
|
||||
((Directory)child).walk(consumer);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2021, 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
|
||||
|
@ -33,7 +33,17 @@ package jdk.internal.jimage;
|
|||
* to the jimage file provided by the shipped JDK by tools running on JDK 8.
|
||||
*/
|
||||
public interface ImageStrings {
|
||||
public String get(int offset);
|
||||
String get(int offset);
|
||||
|
||||
int add(final String string);
|
||||
|
||||
/**
|
||||
* If there's a string at {@code offset} matching in full a substring of
|
||||
* {@code string} starting at {@code stringOffset}, return the length
|
||||
* of that string. Otherwise returns -1. Optional operation.
|
||||
*/
|
||||
default int match(int offset, String string, int stringOffset) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public int add(final String string);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2021, 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
|
||||
|
@ -27,6 +27,7 @@ package jdk.internal.jimage;
|
|||
|
||||
import java.io.UTFDataFormatException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
@ -51,6 +52,11 @@ public class ImageStringsReader implements ImageStrings {
|
|||
return reader.getString(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int match(int offset, String string, int stringOffset) {
|
||||
return reader.match(offset, string, stringOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int add(final String string) {
|
||||
throw new InternalError("Can not add strings at runtime");
|
||||
|
@ -69,9 +75,9 @@ public class ImageStringsReader implements ImageStrings {
|
|||
}
|
||||
|
||||
public static int hashCode(String module, String name, int seed) {
|
||||
seed = unmaskedHashCode("/", seed);
|
||||
seed = (seed * HASH_MULTIPLIER) ^ ('/');
|
||||
seed = unmaskedHashCode(module, seed);
|
||||
seed = unmaskedHashCode("/", seed);
|
||||
seed = (seed * HASH_MULTIPLIER) ^ ('/');
|
||||
seed = unmaskedHashCode(name, seed);
|
||||
return seed & POSITIVE_MASK;
|
||||
}
|
||||
|
@ -81,8 +87,7 @@ public class ImageStringsReader implements ImageStrings {
|
|||
byte[] buffer = null;
|
||||
|
||||
for (int i = 0; i < slen; i++) {
|
||||
char ch = s.charAt(i);
|
||||
int uch = ch & 0xFFFF;
|
||||
int uch = s.charAt(i);
|
||||
|
||||
if ((uch & ~0x7F) != 0) {
|
||||
if (buffer == null) {
|
||||
|
@ -183,29 +188,38 @@ public class ImageStringsReader implements ImageStrings {
|
|||
return stringFromMUTF8(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
static int charsFromByteBufferLength(ByteBuffer buffer) {
|
||||
/**
|
||||
* Calculates the number of characters in the String present at the
|
||||
* specified offset. As an optimization, the length returned will
|
||||
* be positive if the characters are all ASCII, and negative otherwise.
|
||||
*/
|
||||
private static int charsFromByteBufferLength(ByteBuffer buffer, int offset) {
|
||||
int length = 0;
|
||||
|
||||
while(buffer.hasRemaining()) {
|
||||
byte ch = buffer.get();
|
||||
int limit = buffer.limit();
|
||||
boolean asciiOnly = true;
|
||||
while (offset < limit) {
|
||||
byte ch = buffer.get(offset++);
|
||||
|
||||
if (ch == 0) {
|
||||
return length;
|
||||
if (ch < 0) {
|
||||
asciiOnly = false;
|
||||
} else if (ch == 0) {
|
||||
return asciiOnly ? length : -length;
|
||||
}
|
||||
|
||||
if ((ch & 0xC0) != 0x80) {
|
||||
length++;
|
||||
}
|
||||
}
|
||||
|
||||
throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence");
|
||||
}
|
||||
|
||||
static void charsFromByteBuffer(char[] chars, ByteBuffer buffer) {
|
||||
private static void charsFromByteBuffer(char[] chars, ByteBuffer buffer, int offset) {
|
||||
int j = 0;
|
||||
|
||||
while(buffer.hasRemaining()) {
|
||||
byte ch = buffer.get();
|
||||
int limit = buffer.limit();
|
||||
while (offset < limit) {
|
||||
byte ch = buffer.get(offset++);
|
||||
|
||||
if (ch == 0) {
|
||||
return;
|
||||
|
@ -218,7 +232,7 @@ public class ImageStringsReader implements ImageStrings {
|
|||
int mask = 0x40;
|
||||
|
||||
while ((uch & mask) != 0) {
|
||||
ch = buffer.get();
|
||||
ch = buffer.get(offset++);
|
||||
|
||||
if ((ch & 0xC0) != 0x80) {
|
||||
throw new InternalError("Bad continuation in " +
|
||||
|
@ -242,14 +256,62 @@ public class ImageStringsReader implements ImageStrings {
|
|||
}
|
||||
|
||||
public static String stringFromByteBuffer(ByteBuffer buffer) {
|
||||
int length = charsFromByteBufferLength(buffer);
|
||||
buffer.rewind();
|
||||
char[] chars = new char[length];
|
||||
charsFromByteBuffer(chars, buffer);
|
||||
return stringFromByteBuffer(buffer, 0);
|
||||
}
|
||||
|
||||
/* package-private */
|
||||
static String stringFromByteBuffer(ByteBuffer buffer, int offset) {
|
||||
int length = charsFromByteBufferLength(buffer, offset);
|
||||
if (length > 0) {
|
||||
byte[] asciiBytes = new byte[length];
|
||||
// Ideally we could use buffer.get(offset, asciiBytes, 0, length)
|
||||
// here, but that was introduced in JDK 13
|
||||
for (int i = 0; i < length; i++) {
|
||||
asciiBytes[i] = buffer.get(offset++);
|
||||
}
|
||||
return new String(asciiBytes, StandardCharsets.US_ASCII);
|
||||
}
|
||||
char[] chars = new char[-length];
|
||||
charsFromByteBuffer(chars, buffer, offset);
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
/* package-private */
|
||||
static int stringFromByteBufferMatches(ByteBuffer buffer, int offset, String string, int stringOffset) {
|
||||
// ASCII fast-path
|
||||
int limit = buffer.limit();
|
||||
int current = offset;
|
||||
int slen = string.length();
|
||||
while (current < limit) {
|
||||
byte ch = buffer.get(current);
|
||||
if (ch <= 0) {
|
||||
if (ch == 0) {
|
||||
// Match
|
||||
return current - offset;
|
||||
}
|
||||
// non-ASCII byte, run slow-path from current offset
|
||||
break;
|
||||
}
|
||||
if (slen <= stringOffset || string.charAt(stringOffset) != (char)ch) {
|
||||
// No match
|
||||
return -1;
|
||||
}
|
||||
stringOffset++;
|
||||
current++;
|
||||
}
|
||||
// invariant: remainder of the string starting at current is non-ASCII,
|
||||
// so return value from charsFromByteBufferLength will be negative
|
||||
int length = -charsFromByteBufferLength(buffer, current);
|
||||
char[] chars = new char[length];
|
||||
charsFromByteBuffer(chars, buffer, current);
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (string.charAt(stringOffset++) != chars[i]) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static int mutf8FromStringLength(String s) {
|
||||
int length = 0;
|
||||
int slen = s.length();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, 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
|
||||
|
@ -432,11 +432,27 @@ public final class SystemModuleFinders {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given resource exists, {@code false}
|
||||
* if not found.
|
||||
*/
|
||||
private boolean containsImageLocation(String name) throws IOException {
|
||||
Objects.requireNonNull(name);
|
||||
if (closed)
|
||||
throw new IOException("ModuleReader is closed");
|
||||
ImageReader imageReader = SystemImage.reader();
|
||||
if (imageReader != null) {
|
||||
return imageReader.verifyLocation(module, name);
|
||||
} else {
|
||||
// not an images build
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<URI> find(String name) throws IOException {
|
||||
ImageLocation location = findImageLocation(name);
|
||||
if (location != null) {
|
||||
URI u = URI.create("jrt:/" + module + "/" + name);
|
||||
if (containsImageLocation(name)) {
|
||||
URI u = JNUA.create("jrt", "/" + module + "/" + name);
|
||||
return Optional.of(u);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue