Skip to content

Commit b7b5536

Browse files
cushonJavac Team
authored andcommitted
Lazily create BytecodeBoundClass objects
Most of the classes on the classpath are never loaded, and `BytecodeBoundClass` has a relatively expensive constructor that creates a bunch of suppliers to try to defer work until it's needed. Putting yet another lazy supplier in front of the entire `BytecodeBoundClass` makes classes that are never loaded cheaper. PiperOrigin-RevId: 690677848
1 parent 81d79e3 commit b7b5536

File tree

4 files changed

+38
-52
lines changed

4 files changed

+38
-52
lines changed

java/com/google/turbine/binder/ClassPathBinder.java

Lines changed: 14 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package com.google.turbine.binder;
1818

1919
import com.google.common.base.Supplier;
20-
import com.google.common.base.Suppliers;
2120
import com.google.common.collect.ImmutableMap;
2221
import com.google.turbine.binder.bound.ModuleInfo;
2322
import com.google.turbine.binder.bytecode.BytecodeBinder;
@@ -35,7 +34,6 @@
3534
import java.util.HashMap;
3635
import java.util.LinkedHashMap;
3736
import java.util.Map;
38-
import java.util.function.Function;
3937
import org.jspecify.annotations.Nullable;
4038

4139
/** Sets up an environment for symbols on the classpath. */
@@ -55,33 +53,31 @@ public final class ClassPathBinder {
5553

5654
/** Creates an environment containing symbols in the given classpath. */
5755
public static ClassPath bindClasspath(Collection<Path> paths) throws IOException {
58-
// TODO(cushon): this is going to require an env eventually,
59-
// e.g. to look up type parameters in enclosing declarations
60-
Map<ClassSymbol, BytecodeBoundClass> transitive = new LinkedHashMap<>();
61-
Map<ClassSymbol, BytecodeBoundClass> map = new HashMap<>();
56+
Map<ClassSymbol, Supplier<BytecodeBoundClass>> transitive = new LinkedHashMap<>();
57+
Map<ClassSymbol, Supplier<BytecodeBoundClass>> map = new HashMap<>();
6258
Map<ModuleSymbol, ModuleInfo> modules = new HashMap<>();
6359
Map<String, Supplier<byte[]>> resources = new HashMap<>();
64-
Env<ClassSymbol, BytecodeBoundClass> benv =
60+
Env<ClassSymbol, BytecodeBoundClass> env =
6561
new Env<ClassSymbol, BytecodeBoundClass>() {
6662
@Override
6763
public @Nullable BytecodeBoundClass get(ClassSymbol sym) {
68-
return map.get(sym);
64+
Supplier<BytecodeBoundClass> supplier = map.get(sym);
65+
return supplier == null ? null : supplier.get();
6966
}
7067
};
7168
for (Path path : paths) {
7269
try {
73-
bindJar(path, map, modules, benv, transitive, resources);
70+
bindJar(path, map, modules, env, transitive, resources);
7471
} catch (IOException e) {
7572
throw new IOException("error reading " + path, e);
7673
}
7774
}
78-
for (Map.Entry<ClassSymbol, BytecodeBoundClass> entry : transitive.entrySet()) {
75+
for (Map.Entry<ClassSymbol, Supplier<BytecodeBoundClass>> entry : transitive.entrySet()) {
7976
ClassSymbol symbol = entry.getKey();
8077
map.putIfAbsent(symbol, entry.getValue());
8178
}
82-
SimpleEnv<ClassSymbol, BytecodeBoundClass> env = new SimpleEnv<>(ImmutableMap.copyOf(map));
8379
SimpleEnv<ModuleSymbol, ModuleInfo> moduleEnv = new SimpleEnv<>(ImmutableMap.copyOf(modules));
84-
TopLevelIndex index = SimpleTopLevelIndex.of(env.asMap().keySet());
80+
TopLevelIndex index = SimpleTopLevelIndex.of(map.keySet());
8581
return new ClassPath() {
8682
@Override
8783
public Env<ClassSymbol, BytecodeBoundClass> env() {
@@ -107,10 +103,10 @@ public TopLevelIndex index() {
107103

108104
private static void bindJar(
109105
Path path,
110-
Map<ClassSymbol, BytecodeBoundClass> env,
106+
Map<ClassSymbol, Supplier<BytecodeBoundClass>> env,
111107
Map<ModuleSymbol, ModuleInfo> modules,
112108
Env<ClassSymbol, BytecodeBoundClass> benv,
113-
Map<ClassSymbol, BytecodeBoundClass> transitive,
109+
Map<ClassSymbol, Supplier<BytecodeBoundClass>> transitive,
114110
Map<String, Supplier<byte[]>> resources)
115111
throws IOException {
116112
// TODO(cushon): don't leak file descriptors
@@ -124,41 +120,22 @@ private static void bindJar(
124120
new ClassSymbol(
125121
name.substring(
126122
TRANSITIVE_PREFIX.length(), name.length() - TRANSITIVE_SUFFIX.length()));
127-
transitive.computeIfAbsent(
128-
sym,
129-
new Function<ClassSymbol, BytecodeBoundClass>() {
130-
@Override
131-
public BytecodeBoundClass apply(ClassSymbol sym) {
132-
return new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, path.toString());
133-
}
134-
});
123+
transitive.putIfAbsent(sym, BytecodeBoundClass.lazy(sym, ze, benv, path));
135124
continue;
136125
}
137126
if (!name.endsWith(".class")) {
138-
resources.put(name, toByteArrayOrDie(ze));
127+
resources.put(name, ze);
139128
continue;
140129
}
141130
if (name.substring(name.lastIndexOf('/') + 1).equals("module-info.class")) {
142-
ModuleInfo moduleInfo =
143-
BytecodeBinder.bindModuleInfo(path.toString(), toByteArrayOrDie(ze));
131+
ModuleInfo moduleInfo = BytecodeBinder.bindModuleInfo(path.toString(), ze);
144132
modules.put(new ModuleSymbol(moduleInfo.name()), moduleInfo);
145133
continue;
146134
}
147135
ClassSymbol sym = new ClassSymbol(name.substring(0, name.length() - ".class".length()));
148-
env.putIfAbsent(
149-
sym, new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, path.toString()));
136+
env.putIfAbsent(sym, BytecodeBoundClass.lazy(sym, ze, benv, path));
150137
}
151138
}
152139

153-
private static Supplier<byte[]> toByteArrayOrDie(Zip.Entry ze) {
154-
return Suppliers.memoize(
155-
new Supplier<byte[]>() {
156-
@Override
157-
public byte[] get() {
158-
return ze.data();
159-
}
160-
});
161-
}
162-
163140
private ClassPathBinder() {}
164141
}

java/com/google/turbine/binder/CtSymClassBinder.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import com.google.common.annotations.VisibleForTesting;
2323
import com.google.common.base.Supplier;
24-
import com.google.common.base.Suppliers;
2524
import com.google.common.collect.ImmutableMap;
2625
import com.google.turbine.binder.bound.ModuleInfo;
2726
import com.google.turbine.binder.bytecode.BytecodeBinder;
@@ -86,13 +85,12 @@ public final class CtSymClassBinder {
8685
// JDK >= 12 includes the module name as a prefix
8786
idx = name.indexOf('/', idx + 1);
8887
if (name.substring(name.lastIndexOf('/') + 1).equals("module-info.sig")) {
89-
ModuleInfo moduleInfo = BytecodeBinder.bindModuleInfo(name, toByteArrayOrDie(ze));
88+
ModuleInfo moduleInfo = BytecodeBinder.bindModuleInfo(name, ze);
9089
modules.put(new ModuleSymbol(moduleInfo.name()), moduleInfo);
9190
continue;
9291
}
9392
ClassSymbol sym = new ClassSymbol(name.substring(idx + 1, name.length() - ".sig".length()));
94-
map.putIfAbsent(
95-
sym, new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, ctSym + "!" + ze.name()));
93+
map.putIfAbsent(sym, new BytecodeBoundClass(sym, ze, benv, ctSym + "!" + ze.name()));
9694
}
9795
if (map.isEmpty()) {
9896
// we didn't find any classes for the desired release
@@ -124,16 +122,6 @@ public TopLevelIndex index() {
124122
};
125123
}
126124

127-
private static Supplier<byte[]> toByteArrayOrDie(Zip.Entry ze) {
128-
return Suppliers.memoize(
129-
new Supplier<byte[]>() {
130-
@Override
131-
public byte[] get() {
132-
return ze.data();
133-
}
134-
});
135-
}
136-
137125
// ct.sym contains directories whose names are the concatenation of a list of target versions
138126
// formatted as a single character 0-9 or A-Z (e.g. 789A) and which contain interface class
139127
// files with a .sig extension.

java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import com.google.turbine.type.Type.ClassTy;
5959
import com.google.turbine.type.Type.IntersectionTy;
6060
import java.lang.annotation.RetentionPolicy;
61+
import java.nio.file.Path;
6162
import java.util.List;
6263
import java.util.Map;
6364
import org.jspecify.annotations.Nullable;
@@ -72,6 +73,20 @@
7273
*/
7374
public class BytecodeBoundClass implements TypeBoundClass {
7475

76+
public static Supplier<BytecodeBoundClass> lazy(
77+
ClassSymbol sym,
78+
Supplier<byte[]> bytes,
79+
Env<ClassSymbol, BytecodeBoundClass> env,
80+
Path path) {
81+
return Suppliers.memoize(
82+
new Supplier<BytecodeBoundClass>() {
83+
@Override
84+
public BytecodeBoundClass get() {
85+
return new BytecodeBoundClass(sym, bytes, env, path.toString());
86+
}
87+
});
88+
}
89+
7590
private final ClassSymbol sym;
7691
private final Env<ClassSymbol, BytecodeBoundClass> env;
7792
private final Supplier<ClassFile> classFile;

java/com/google/turbine/zip/Zip.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static java.nio.charset.StandardCharsets.UTF_8;
2020

21+
import com.google.common.base.Supplier;
2122
import com.google.common.primitives.UnsignedInts;
2223
import java.io.ByteArrayInputStream;
2324
import java.io.Closeable;
@@ -251,7 +252,7 @@ public void close() throws IOException {
251252
}
252253

253254
/** An entry in a zip archive. */
254-
public static class Entry {
255+
public static class Entry implements Supplier<byte[]> {
255256

256257
private final Path path;
257258
private final FileChannel chan;
@@ -351,6 +352,11 @@ private byte[] getBytes(
351352
throw new IOError(e);
352353
}
353354
}
355+
356+
@Override
357+
public byte[] get() {
358+
return data();
359+
}
354360
}
355361

356362
static void checkSignature(

0 commit comments

Comments
 (0)