Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazily create BytecodeBoundClass objects #352

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 14 additions & 37 deletions java/com/google/turbine/binder/ClassPathBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package com.google.turbine.binder;

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.bound.ModuleInfo;
import com.google.turbine.binder.bytecode.BytecodeBinder;
Expand All @@ -35,7 +34,6 @@
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;
import org.jspecify.annotations.Nullable;

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

/** Creates an environment containing symbols in the given classpath. */
public static ClassPath bindClasspath(Collection<Path> paths) throws IOException {
// TODO(cushon): this is going to require an env eventually,
// e.g. to look up type parameters in enclosing declarations
Map<ClassSymbol, BytecodeBoundClass> transitive = new LinkedHashMap<>();
Map<ClassSymbol, BytecodeBoundClass> map = new HashMap<>();
Map<ClassSymbol, Supplier<BytecodeBoundClass>> transitive = new LinkedHashMap<>();
Map<ClassSymbol, Supplier<BytecodeBoundClass>> map = new HashMap<>();
Map<ModuleSymbol, ModuleInfo> modules = new HashMap<>();
Map<String, Supplier<byte[]>> resources = new HashMap<>();
Env<ClassSymbol, BytecodeBoundClass> benv =
Env<ClassSymbol, BytecodeBoundClass> env =
new Env<ClassSymbol, BytecodeBoundClass>() {
@Override
public @Nullable BytecodeBoundClass get(ClassSymbol sym) {
return map.get(sym);
Supplier<BytecodeBoundClass> supplier = map.get(sym);
return supplier == null ? null : supplier.get();
}
};
for (Path path : paths) {
try {
bindJar(path, map, modules, benv, transitive, resources);
bindJar(path, map, modules, env, transitive, resources);
} catch (IOException e) {
throw new IOException("error reading " + path, e);
}
}
for (Map.Entry<ClassSymbol, BytecodeBoundClass> entry : transitive.entrySet()) {
for (Map.Entry<ClassSymbol, Supplier<BytecodeBoundClass>> entry : transitive.entrySet()) {
ClassSymbol symbol = entry.getKey();
map.putIfAbsent(symbol, entry.getValue());
}
SimpleEnv<ClassSymbol, BytecodeBoundClass> env = new SimpleEnv<>(ImmutableMap.copyOf(map));
SimpleEnv<ModuleSymbol, ModuleInfo> moduleEnv = new SimpleEnv<>(ImmutableMap.copyOf(modules));
TopLevelIndex index = SimpleTopLevelIndex.of(env.asMap().keySet());
TopLevelIndex index = SimpleTopLevelIndex.of(map.keySet());
return new ClassPath() {
@Override
public Env<ClassSymbol, BytecodeBoundClass> env() {
Expand All @@ -107,10 +103,10 @@ public TopLevelIndex index() {

private static void bindJar(
Path path,
Map<ClassSymbol, BytecodeBoundClass> env,
Map<ClassSymbol, Supplier<BytecodeBoundClass>> env,
Map<ModuleSymbol, ModuleInfo> modules,
Env<ClassSymbol, BytecodeBoundClass> benv,
Map<ClassSymbol, BytecodeBoundClass> transitive,
Map<ClassSymbol, Supplier<BytecodeBoundClass>> transitive,
Map<String, Supplier<byte[]>> resources)
throws IOException {
// TODO(cushon): don't leak file descriptors
Expand All @@ -124,41 +120,22 @@ private static void bindJar(
new ClassSymbol(
name.substring(
TRANSITIVE_PREFIX.length(), name.length() - TRANSITIVE_SUFFIX.length()));
transitive.computeIfAbsent(
sym,
new Function<ClassSymbol, BytecodeBoundClass>() {
@Override
public BytecodeBoundClass apply(ClassSymbol sym) {
return new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, path.toString());
}
});
transitive.putIfAbsent(sym, BytecodeBoundClass.lazy(sym, ze, benv, path));
continue;
}
if (!name.endsWith(".class")) {
resources.put(name, toByteArrayOrDie(ze));
resources.put(name, ze);
continue;
}
if (name.substring(name.lastIndexOf('/') + 1).equals("module-info.class")) {
ModuleInfo moduleInfo =
BytecodeBinder.bindModuleInfo(path.toString(), toByteArrayOrDie(ze));
ModuleInfo moduleInfo = BytecodeBinder.bindModuleInfo(path.toString(), ze);
modules.put(new ModuleSymbol(moduleInfo.name()), moduleInfo);
continue;
}
ClassSymbol sym = new ClassSymbol(name.substring(0, name.length() - ".class".length()));
env.putIfAbsent(
sym, new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, path.toString()));
env.putIfAbsent(sym, BytecodeBoundClass.lazy(sym, ze, benv, path));
}
}

private static Supplier<byte[]> toByteArrayOrDie(Zip.Entry ze) {
return Suppliers.memoize(
new Supplier<byte[]>() {
@Override
public byte[] get() {
return ze.data();
}
});
}

private ClassPathBinder() {}
}
16 changes: 2 additions & 14 deletions java/com/google/turbine/binder/CtSymClassBinder.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.turbine.binder.bound.ModuleInfo;
import com.google.turbine.binder.bytecode.BytecodeBinder;
Expand Down Expand Up @@ -86,13 +85,12 @@ public final class CtSymClassBinder {
// JDK >= 12 includes the module name as a prefix
idx = name.indexOf('/', idx + 1);
if (name.substring(name.lastIndexOf('/') + 1).equals("module-info.sig")) {
ModuleInfo moduleInfo = BytecodeBinder.bindModuleInfo(name, toByteArrayOrDie(ze));
ModuleInfo moduleInfo = BytecodeBinder.bindModuleInfo(name, ze);
modules.put(new ModuleSymbol(moduleInfo.name()), moduleInfo);
continue;
}
ClassSymbol sym = new ClassSymbol(name.substring(idx + 1, name.length() - ".sig".length()));
map.putIfAbsent(
sym, new BytecodeBoundClass(sym, toByteArrayOrDie(ze), benv, ctSym + "!" + ze.name()));
map.putIfAbsent(sym, new BytecodeBoundClass(sym, ze, benv, ctSym + "!" + ze.name()));
}
if (map.isEmpty()) {
// we didn't find any classes for the desired release
Expand Down Expand Up @@ -124,16 +122,6 @@ public TopLevelIndex index() {
};
}

private static Supplier<byte[]> toByteArrayOrDie(Zip.Entry ze) {
return Suppliers.memoize(
new Supplier<byte[]>() {
@Override
public byte[] get() {
return ze.data();
}
});
}

// ct.sym contains directories whose names are the concatenation of a list of target versions
// formatted as a single character 0-9 or A-Z (e.g. 789A) and which contain interface class
// files with a .sig extension.
Expand Down
15 changes: 15 additions & 0 deletions java/com/google/turbine/binder/bytecode/BytecodeBoundClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import com.google.turbine.type.Type.ClassTy;
import com.google.turbine.type.Type.IntersectionTy;
import java.lang.annotation.RetentionPolicy;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import org.jspecify.annotations.Nullable;
Expand All @@ -72,6 +73,20 @@
*/
public class BytecodeBoundClass implements TypeBoundClass {

public static Supplier<BytecodeBoundClass> lazy(
ClassSymbol sym,
Supplier<byte[]> bytes,
Env<ClassSymbol, BytecodeBoundClass> env,
Path path) {
return Suppliers.memoize(
new Supplier<BytecodeBoundClass>() {
@Override
public BytecodeBoundClass get() {
return new BytecodeBoundClass(sym, bytes, env, path.toString());
}
});
}

private final ClassSymbol sym;
private final Env<ClassSymbol, BytecodeBoundClass> env;
private final Supplier<ClassFile> classFile;
Expand Down
8 changes: 7 additions & 1 deletion java/com/google/turbine/zip/Zip.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

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

import com.google.common.base.Supplier;
import com.google.common.primitives.UnsignedInts;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
Expand Down Expand Up @@ -251,7 +252,7 @@ public void close() throws IOException {
}

/** An entry in a zip archive. */
public static class Entry {
public static class Entry implements Supplier<byte[]> {

private final Path path;
private final FileChannel chan;
Expand Down Expand Up @@ -351,6 +352,11 @@ private byte[] getBytes(
throw new IOError(e);
}
}

@Override
public byte[] get() {
return data();
}
}

static void checkSignature(
Expand Down
Loading