Skip to content

Commit 2f893c2

Browse files
committed
8260337: Optimize ImageReader lookup, used by Class.getResource
Reviewed-by: jlaskey, sundar
1 parent f0bd9db commit 2f893c2

File tree

8 files changed

+330
-130
lines changed

8 files changed

+330
-130
lines changed

src/java.base/share/classes/java/lang/Class.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -3048,15 +3048,19 @@ private static void checkPackageAccessForPermittedSubclasses(SecurityManager sm,
30483048
}
30493049

30503050
/**
3051-
* Add a package name prefix if the name is not absolute Remove leading "/"
3051+
* Add a package name prefix if the name is not absolute. Remove leading "/"
30523052
* if name is absolute
30533053
*/
30543054
private String resolveName(String name) {
30553055
if (!name.startsWith("/")) {
3056-
Class<?> c = isArray() ? elementType() : this;
3057-
String baseName = c.getPackageName();
3056+
String baseName = getPackageName();
30583057
if (baseName != null && !baseName.isEmpty()) {
3059-
name = baseName.replace('.', '/') + "/" + name;
3058+
int len = baseName.length() + 1 + name.length();
3059+
StringBuilder sb = new StringBuilder(len);
3060+
name = sb.append(baseName.replace('.', '/'))
3061+
.append('/')
3062+
.append(name)
3063+
.toString();
30603064
}
30613065
} else {
30623066
name = name.substring(1);

src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java

+51-36
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -249,57 +249,69 @@ public ImageStringsReader getStrings() {
249249
return stringsReader;
250250
}
251251

252-
public synchronized ImageLocation findLocation(String module, String name) {
253-
Objects.requireNonNull(module);
254-
Objects.requireNonNull(name);
255-
// Details of the algorithm used here can be found in
256-
// jdk.tools.jlink.internal.PerfectHashBuilder.
257-
int count = header.getTableLength();
258-
int index = redirect.get(ImageStringsReader.hashCode(module, name) % count);
259-
252+
public ImageLocation findLocation(String module, String name) {
253+
int index = getLocationIndex(module, name);
260254
if (index < 0) {
261-
// index is twos complement of location attributes index.
262-
index = -index - 1;
263-
} else if (index > 0) {
264-
// index is hash seed needed to compute location attributes index.
265-
index = ImageStringsReader.hashCode(module, name, index) % count;
266-
} else {
267-
// No entry.
268255
return null;
269256
}
270-
271257
long[] attributes = getAttributes(offsets.get(index));
272-
273258
if (!ImageLocation.verify(module, name, attributes, stringsReader)) {
274259
return null;
275260
}
276261
return new ImageLocation(attributes, stringsReader);
277262
}
278263

279-
public synchronized ImageLocation findLocation(String name) {
280-
Objects.requireNonNull(name);
281-
// Details of the algorithm used here can be found in
282-
// jdk.tools.jlink.internal.PerfectHashBuilder.
264+
public ImageLocation findLocation(String name) {
265+
int index = getLocationIndex(name);
266+
if (index < 0) {
267+
return null;
268+
}
269+
long[] attributes = getAttributes(offsets.get(index));
270+
if (!ImageLocation.verify(name, attributes, stringsReader)) {
271+
return null;
272+
}
273+
return new ImageLocation(attributes, stringsReader);
274+
}
275+
276+
public boolean verifyLocation(String module, String name) {
277+
int index = getLocationIndex(module, name);
278+
if (index < 0) {
279+
return false;
280+
}
281+
int locationOffset = offsets.get(index);
282+
return ImageLocation.verify(module, name, locations, locationOffset, stringsReader);
283+
}
284+
285+
// Details of the algorithm used here can be found in
286+
// jdk.tools.jlink.internal.PerfectHashBuilder.
287+
public int getLocationIndex(String name) {
283288
int count = header.getTableLength();
284289
int index = redirect.get(ImageStringsReader.hashCode(name) % count);
285-
286290
if (index < 0) {
287291
// index is twos complement of location attributes index.
288-
index = -index - 1;
292+
return -index - 1;
289293
} else if (index > 0) {
290294
// index is hash seed needed to compute location attributes index.
291-
index = ImageStringsReader.hashCode(name, index) % count;
295+
return ImageStringsReader.hashCode(name, index) % count;
292296
} else {
293297
// No entry.
294-
return null;
298+
return -1;
295299
}
300+
}
296301

297-
long[] attributes = getAttributes(offsets.get(index));
298-
299-
if (!ImageLocation.verify(name, attributes, stringsReader)) {
300-
return null;
302+
private int getLocationIndex(String module, String name) {
303+
int count = header.getTableLength();
304+
int index = redirect.get(ImageStringsReader.hashCode(module, name) % count);
305+
if (index < 0) {
306+
// index is twos complement of location attributes index.
307+
return -index - 1;
308+
} else if (index > 0) {
309+
// index is hash seed needed to compute location attributes index.
310+
return ImageStringsReader.hashCode(module, name, index) % count;
311+
} else {
312+
// No entry.
313+
return -1;
301314
}
302-
return new ImageLocation(attributes, stringsReader);
303315
}
304316

305317
public String[] getEntryNames() {
@@ -320,18 +332,21 @@ public long[] getAttributes(int offset) {
320332
if (offset < 0 || offset >= locations.limit()) {
321333
throw new IndexOutOfBoundsException("offset");
322334
}
323-
324-
ByteBuffer buffer = slice(locations, offset, locations.limit() - offset);
325-
return ImageLocation.decompress(buffer);
335+
return ImageLocation.decompress(locations, offset);
326336
}
327337

328338
public String getString(int offset) {
329339
if (offset < 0 || offset >= strings.limit()) {
330340
throw new IndexOutOfBoundsException("offset");
331341
}
342+
return ImageStringsReader.stringFromByteBuffer(strings, offset);
343+
}
332344

333-
ByteBuffer buffer = slice(strings, offset, strings.limit() - offset);
334-
return ImageStringsReader.stringFromByteBuffer(buffer);
345+
public int match(int offset, String string, int stringOffset) {
346+
if (offset < 0 || offset >= strings.limit()) {
347+
throw new IndexOutOfBoundsException("offset");
348+
}
349+
return ImageStringsReader.stringFromByteBufferMatches(strings, offset, string, stringOffset);
335350
}
336351

337352
private byte[] getBufferBytes(ByteBuffer buffer) {

src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java

+99-62
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -59,41 +59,26 @@ ImageStrings getStrings() {
5959
return strings;
6060
}
6161

62-
static long[] decompress(ByteBuffer bytes) {
62+
static long[] decompress(ByteBuffer bytes, int offset) {
6363
Objects.requireNonNull(bytes);
6464
long[] attributes = new long[ATTRIBUTE_COUNT];
6565

66-
if (bytes != null) {
67-
while (bytes.hasRemaining()) {
68-
int data = bytes.get() & 0xFF;
69-
int kind = data >>> 3;
70-
71-
if (kind == ATTRIBUTE_END) {
72-
break;
73-
}
74-
75-
if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
76-
throw new InternalError(
77-
"Invalid jimage attribute kind: " + kind);
78-
}
79-
80-
int length = (data & 0x7) + 1;
81-
long value = 0;
82-
83-
for (int j = 0; j < length; j++) {
84-
value <<= 8;
85-
86-
if (!bytes.hasRemaining()) {
87-
throw new InternalError("Missing jimage attribute data");
88-
}
89-
90-
value |= bytes.get() & 0xFF;
91-
}
92-
93-
attributes[kind] = value;
66+
int limit = bytes.limit();
67+
while (offset < limit) {
68+
int data = bytes.get(offset++) & 0xFF;
69+
if (data <= 0x7) { // ATTRIBUTE_END
70+
break;
71+
}
72+
int kind = data >>> 3;
73+
if (ATTRIBUTE_COUNT <= kind) {
74+
throw new InternalError(
75+
"Invalid jimage attribute kind: " + kind);
9476
}
95-
}
9677

78+
int length = (data & 0x7) + 1;
79+
attributes[kind] = readValue(length, bytes, offset, limit);
80+
offset += length;
81+
}
9782
return attributes;
9883
}
9984

@@ -126,71 +111,125 @@ public boolean verify(String name) {
126111
/**
127112
* A simpler verification would be {@code name.equals(getFullName())}, but
128113
* by not creating the full name and enabling early returns we allocate
129-
* fewer objects. Could possibly be made allocation free by extending
130-
* ImageStrings to test if strings at an offset match the name region.
114+
* fewer objects.
131115
*/
132116
static boolean verify(String name, long[] attributes, ImageStrings strings) {
133117
Objects.requireNonNull(name);
134118
final int length = name.length();
135119
int index = 0;
136120
int moduleOffset = (int)attributes[ATTRIBUTE_MODULE];
137-
if (moduleOffset != 0) {
138-
String module = strings.get(moduleOffset);
139-
final int moduleLen = module.length();
121+
if (moduleOffset != 0 && length >= 1) {
122+
int moduleLen = strings.match(moduleOffset, name, 1);
140123
index = moduleLen + 1;
141-
if (length <= index
124+
if (moduleLen < 0
125+
|| length <= index
142126
|| name.charAt(0) != '/'
143-
|| !name.regionMatches(1, module, 0, moduleLen)
144127
|| name.charAt(index++) != '/') {
145128
return false;
146129
}
147130
}
131+
return verifyName(null, name, index, length, 0,
132+
(int) attributes[ATTRIBUTE_PARENT],
133+
(int) attributes[ATTRIBUTE_BASE],
134+
(int) attributes[ATTRIBUTE_EXTENSION],
135+
strings);
136+
}
148137

149-
return verifyName(name, index, length, attributes, strings);
138+
static boolean verify(String module, String name, ByteBuffer locations,
139+
int locationOffset, ImageStrings strings) {
140+
int moduleOffset = 0;
141+
int parentOffset = 0;
142+
int baseOffset = 0;
143+
int extOffset = 0;
144+
145+
int limit = locations.limit();
146+
while (locationOffset < limit) {
147+
int data = locations.get(locationOffset++) & 0xFF;
148+
if (data <= 0x7) { // ATTRIBUTE_END
149+
break;
150+
}
151+
int kind = data >>> 3;
152+
if (ATTRIBUTE_COUNT <= kind) {
153+
throw new InternalError(
154+
"Invalid jimage attribute kind: " + kind);
155+
}
156+
157+
int length = (data & 0x7) + 1;
158+
switch (kind) {
159+
case ATTRIBUTE_MODULE:
160+
moduleOffset = (int) readValue(length, locations, locationOffset, limit);
161+
break;
162+
case ATTRIBUTE_BASE:
163+
baseOffset = (int) readValue(length, locations, locationOffset, limit);
164+
break;
165+
case ATTRIBUTE_PARENT:
166+
parentOffset = (int) readValue(length, locations, locationOffset, limit);
167+
break;
168+
case ATTRIBUTE_EXTENSION:
169+
extOffset = (int) readValue(length, locations, locationOffset, limit);
170+
break;
171+
}
172+
locationOffset += length;
173+
}
174+
return verifyName(module, name, 0, name.length(),
175+
moduleOffset, parentOffset, baseOffset, extOffset, strings);
176+
}
177+
178+
private static long readValue(int length, ByteBuffer buffer, int offset, int limit) {
179+
long value = 0;
180+
for (int j = 0; j < length; j++) {
181+
value <<= 8;
182+
if (offset >= limit) {
183+
throw new InternalError("Missing jimage attribute data");
184+
}
185+
value |= buffer.get(offset++) & 0xFF;
186+
}
187+
return value;
150188
}
151189

152190
static boolean verify(String module, String name, long[] attributes,
153191
ImageStrings strings) {
154192
Objects.requireNonNull(module);
155193
Objects.requireNonNull(name);
156-
int moduleOffset = (int)attributes[ATTRIBUTE_MODULE];
194+
return verifyName(module, name, 0, name.length(),
195+
(int) attributes[ATTRIBUTE_MODULE],
196+
(int) attributes[ATTRIBUTE_PARENT],
197+
(int) attributes[ATTRIBUTE_BASE],
198+
(int) attributes[ATTRIBUTE_EXTENSION],
199+
strings);
200+
}
201+
202+
private static boolean verifyName(String module, String name, int index, int length,
203+
int moduleOffset, int parentOffset, int baseOffset, int extOffset, ImageStrings strings) {
204+
157205
if (moduleOffset != 0) {
158-
if (!module.equals(strings.get(moduleOffset))) {
206+
if (strings.match(moduleOffset, module, 0) != module.length()) {
159207
return false;
160208
}
161209
}
162-
163-
return verifyName(name, 0, name.length(), attributes, strings);
164-
}
165-
166-
private static boolean verifyName(String name, int index, int length,
167-
long[] attributes, ImageStrings strings) {
168-
169-
int parentOffset = (int) attributes[ATTRIBUTE_PARENT];
170210
if (parentOffset != 0) {
171-
String parent = strings.get(parentOffset);
172-
final int parentLen = parent.length();
173-
if (!name.regionMatches(index, parent, 0, parentLen)) {
211+
int parentLen = strings.match(parentOffset, name, index);
212+
if (parentLen < 0) {
174213
return false;
175214
}
176215
index += parentLen;
177216
if (length <= index || name.charAt(index++) != '/') {
178217
return false;
179218
}
180219
}
181-
String base = strings.get((int) attributes[ATTRIBUTE_BASE]);
182-
final int baseLen = base.length();
183-
if (!name.regionMatches(index, base, 0, baseLen)) {
220+
int baseLen = strings.match(baseOffset, name, index);
221+
if (baseLen < 0) {
184222
return false;
185223
}
186224
index += baseLen;
187-
int extOffset = (int) attributes[ATTRIBUTE_EXTENSION];
188225
if (extOffset != 0) {
189-
String extension = strings.get(extOffset);
190-
int extLen = extension.length();
191226
if (length <= index
192-
|| name.charAt(index++) != '.'
193-
|| !name.regionMatches(index, extension, 0, extLen)) {
227+
|| name.charAt(index++) != '.') {
228+
return false;
229+
}
230+
231+
int extLen = strings.match(extOffset, name, index);
232+
if (extLen < 0) {
194233
return false;
195234
}
196235
index += extLen;
@@ -203,7 +242,6 @@ long getAttribute(int kind) {
203242
throw new InternalError(
204243
"Invalid jimage attribute kind: " + kind);
205244
}
206-
207245
return attributes[kind];
208246
}
209247

@@ -212,7 +250,6 @@ String getAttributeString(int kind) {
212250
throw new InternalError(
213251
"Invalid jimage attribute kind: " + kind);
214252
}
215-
216253
return getStrings().get((int)attributes[kind]);
217254
}
218255

0 commit comments

Comments
 (0)