8161067: jlink: Enable plugins to use the module pool for class lookup

Reviewed-by: sundar, psandoz
This commit is contained in:
Jim Laskey 2016-07-12 10:58:58 -03:00
parent d5e84de014
commit e4226ff2f2
6 changed files with 73 additions and 18 deletions

View File

@ -399,6 +399,14 @@ public final class ImagePluginStack {
return res.isPresent()? Optional.of(getUncompressed(res.get())) : Optional.empty();
}
@Override
public Optional<ModuleEntry> findEntryInContext(String path, ModuleEntry context) {
Objects.requireNonNull(path);
Objects.requireNonNull(context);
Optional<ModuleEntry> res = pool.findEntryInContext(path, context);
return res.map(this::getUncompressed);
}
@Override
public boolean contains(ModuleEntry res) {
return pool.contains(res);

View File

@ -51,16 +51,32 @@ public final class ModuleEntryFactory {
original.getPath(), original.getType(), file);
}
private static String moduleFrom(String path) {
static String moduleFrom(String path) {
Objects.requireNonNull(path);
if (path.isEmpty() || path.charAt(0) != '/') {
throw new IllegalArgumentException(path + " must start with /");
}
String noRoot = path.substring(1);
int idx = noRoot.indexOf('/');
int idx = path.indexOf('/', 1);
if (idx == -1) {
throw new IllegalArgumentException("/ missing after module: " + path);
}
return noRoot.substring(0, idx);
return path.substring(1, idx);
}
static String packageFrom(String path) {
Objects.requireNonNull(path);
int idx = path.lastIndexOf('/');
if (idx == -1) {
throw new IllegalArgumentException("/ missing from path: " + path);
}
if (path.startsWith("/")) {
int jdx = path.indexOf('/', 1);
if (jdx == -1) {
throw new IllegalArgumentException("/ missing after module: " + path);
}
return path.substring(jdx + 1, idx);
} else {
return path.substring(0, idx);
}
}
}

View File

@ -264,6 +264,25 @@ public class ModulePoolImpl implements ModulePool {
return Optional.ofNullable(resources.get(path));
}
/**
* Get the ModuleEntry for the passed path restricted to supplied context.
*
* @param path A data path
* @param context A context of the search
* @return A ModuleEntry instance or null if the data is not found
*/
@Override
public Optional<ModuleEntry> findEntryInContext(String path, ModuleEntry context) {
Objects.requireNonNull(path);
Objects.requireNonNull(context);
LinkModule module = modules.get(context.getModule());
Objects.requireNonNull(module);
Optional<ModuleEntry> entry = module.findEntry(path);
// Navigating other modules via requires and exports is problematic
// since we cannot construct the runtime model of loaders and layers.
return entry;
}
/**
* Check if the ModulePool contains the given ModuleEntry.
*

View File

@ -28,7 +28,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.Optional;
import jdk.tools.jlink.plugin.ModulePool;
import jdk.tools.jlink.plugin.Plugin.Category;
import jdk.internal.org.objectweb.asm.ClassReader;
@ -67,7 +67,7 @@ public final class ClassForNamePlugin implements Plugin {
return index == -1 ? "" : binaryName.substring(0, index);
}
private ModuleEntry transform(ModuleEntry resource, Map<String, ModuleEntry> classes) {
private ModuleEntry transform(ModuleEntry resource, ModulePool pool) {
byte[] inBytes = resource.getBytes();
ClassReader cr = new ClassReader(inBytes);
ClassNode cn = new ClassNode();
@ -96,10 +96,11 @@ public final class ClassForNamePlugin implements Plugin {
min.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) {
String ldcClassName = ldc.cst.toString();
String thatClassName = ldcClassName.replaceAll("\\.", "/");
ModuleEntry thatClass = classes.get(thatClassName);
Optional<ModuleEntry> thatClass =
pool.findEntryInContext(thatClassName + ".class", resource);
if (thatClass != null) {
int thatAccess = getAccess(thatClass);
if (thatClass.isPresent()) {
int thatAccess = getAccess(thatClass.get());
String thatPackage = getPackage(thatClassName);
if ((thatAccess & Opcodes.ACC_PRIVATE) != Opcodes.ACC_PRIVATE &&
@ -142,19 +143,13 @@ public final class ClassForNamePlugin implements Plugin {
public void visit(ModulePool in, ModulePool out) {
Objects.requireNonNull(in);
Objects.requireNonNull(out);
Map<String, ModuleEntry> classes = in.entries()
.filter(resource -> resource != null &&
resource.getPath().endsWith(".class") &&
!resource.getPath().endsWith("/module-info.class"))
.collect(Collectors.toMap(resource -> binaryClassName(resource.getPath()),
resource -> resource));
in.entries()
.filter(resource -> resource != null)
.forEach(resource -> {
String path = resource.getPath();
if (path.endsWith(".class") && !path.endsWith("/module-info.class")) {
out.add(transform(resource, classes));
out.add(transform(resource, in));
} else {
out.add(resource);
}

View File

@ -89,7 +89,16 @@ public interface ModulePool {
* @param path A data path
* @return A ModuleEntry instance or null if the data is not found
*/
public Optional<ModuleEntry> findEntry(String path);
public Optional<ModuleEntry> findEntry(String path);
/**
* Get the ModuleEntry for the passed path restricted to supplied context.
*
* @param path A data path
* @param context A context of the search
* @return A ModuleEntry instance or null if the data is not found
*/
public Optional<ModuleEntry> findEntryInContext(String path, ModuleEntry context);
/**
* Check if the ModulePool contains the given ModuleEntry.

View File

@ -75,5 +75,13 @@ public class JLinkPluginsTest {
Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
helper.checkImage(imageDir, moduleName, res, null);
}
{
// Optimize Class.forName
String[] userOptions = {"--class-for-name"};
String moduleName = "classforname";
helper.generateDefaultJModule(moduleName, "composite2");
Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
helper.checkImage(imageDir, moduleName, null, null);
}
}
}