8143081: [ctw] Test CompileTheWorld.java needs to be updated for Jigsaw
Reviewed-by: iignatyev
--- a/hotspot/test/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java Mon Jun 27 17:23:15 2016 +0300
+++ b/hotspot/test/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java Tue Jun 28 19:58:15 2016 +0300
@@ -28,6 +28,8 @@
import sun.hotspot.code.NMethod;
import sun.hotspot.cpuinfo.CPUInfo;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
--- a/hotspot/test/testlibrary/ctw/Makefile Mon Jun 27 17:23:15 2016 +0300
+++ b/hotspot/test/testlibrary/ctw/Makefile Tue Jun 28 19:58:15 2016 +0300
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2016. 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
@@ -35,12 +35,13 @@
SRC_DIR = src
BUILD_DIR = build
OUTPUT_DIR = $(BUILD_DIR)/classes
-WHITEBOX_DIR = ../whitebox
+TESTLIBRARY_DIR = ../../../../test/lib
JAVAC = $(JDK_HOME)/bin/javac
JAR = $(JDK_HOME)/bin/jar
-SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
+SRC_FILES = $(shell find $(SRC_DIR) $(TESTLIBRARY_DIR)/share/classes -name '*.java')
+WB_SRC_FILES = $(shell find $(TESTLIBRARY_DIR)/sun/hotspot -name '*.java')
MAIN_CLASS = sun.hotspot.tools.ctw.CompileTheWorld
@@ -52,22 +53,29 @@
@rm -rf ctw.jar wb.jar
cleantmp:
- @rm -rf filelist manifest.mf
+ @rm -rf filelist wb_filelist manifest.mf
@rm -rf $(BUILD_DIR)
-ctw.jar: filelist wb.jar manifest.mf
+ctw.jar: filelist wb.jar
@mkdir -p $(OUTPUT_DIR)
- $(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp wb.jar @filelist
- $(JAR) cfm ctw.jar manifest.mf -C $(OUTPUT_DIR) .
+ $(JAVAC) -XaddExports:java.base/jdk.internal.jimage=ALL-UNNAMED \
+ -XaddExports:java.base/jdk.internal.misc=ALL-UNNAMED \
+ -XaddExports:java.base/jdk.internal.reflect=ALL-UNNAMED \
+ -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp wb.jar @filelist
+ $(JAR) --create --file=$@ --main-class $(MAIN_CLASS) -C $(OUTPUT_DIR) .
-wb.jar:
- make -C ${WHITEBOX_DIR} wb.jar
- cp ${WHITEBOX_DIR}/wb.jar ./
- make -C ${WHITEBOX_DIR} clean
+wb.jar: wb_filelist
+ @mkdir -p $(OUTPUT_DIR)
+ $(JAVAC) -sourcepath $(TESTLIBRARY_DIR) \
+ -d $(OUTPUT_DIR) \
+ -cp $(OUTPUT_DIR) \
+ @wb_filelist
+ $(JAR) --create --file=$@ -C $(OUTPUT_DIR) .
+
+wb_filelist: $(WB_SRC_FILES)
+ @rm -f $@
+ @echo $(WB_SRC_FILES) > $@
filelist: $(SRC_FILES)
@rm -f $@
@echo $(SRC_FILES) > $@
-
-manifest.mf:
- @echo "Main-Class: ${MAIN_CLASS}" > manifest.mf
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java Mon Jun 27 17:23:15 2016 +0300
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java Tue Jun 28 19:58:15 2016 +0300
@@ -54,7 +54,7 @@
@Override
public void process() {
- System.out.println("# dir: " + root);
+ CompileTheWorld.OUT.println("# dir: " + root);
if (!Files.exists(root)) {
return;
}
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java Mon Jun 27 17:23:15 2016 +0300
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java Tue Jun 28 19:58:15 2016 +0300
@@ -50,7 +50,7 @@
@Override
public void process() {
- System.out.println("# jar: " + root);
+ CompileTheWorld.OUT.println("# jar: " + root);
if (!Files.exists(root)) {
return;
}
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java Mon Jun 27 17:23:15 2016 +0300
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java Tue Jun 28 19:58:15 2016 +0300
@@ -40,7 +40,7 @@
@Override
public void process() {
- System.out.println("# jar_in_dir: " + root);
+ CompileTheWorld.OUT.println("# jar_in_dir: " + root);
if (!Files.exists(root)) {
return;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJimageEntry.java Tue Jun 28 19:58:15 2016 +0300
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.hotspot.tools.ctw;
+
+import jdk.internal.jimage.ImageReader;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.concurrent.Executor;
+
+/**
+ * Handler for jimage-files containing classes to compile.
+ */
+public class ClassPathJimageEntry extends PathHandler {
+ public ClassPathJimageEntry(Path root, Executor executor) {
+ super(root, executor);
+ try {
+ URL url = root.toUri().toURL();
+ setLoader(new URLClassLoader(new URL[]{url}));
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void process() {
+ CompileTheWorld.OUT.println("# jimage: " + root);
+ if (!Files.exists(root)) {
+ return;
+ }
+ try {
+ ImageReader reader = ImageReader.open(root);
+ Arrays.stream(reader.getEntryNames())
+ .filter(name -> name.endsWith(".class"))
+ .filter(name -> !name.endsWith("module-info.class"))
+ .map(Utils::fileNameToClassName)
+ .forEach(this::processClass);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+}
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java Mon Jun 27 17:23:15 2016 +0300
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java Tue Jun 28 19:58:15 2016 +0300
@@ -40,7 +40,7 @@
@Override
public void process() {
- System.out.println("# list: " + root);
+ CompileTheWorld.OUT.println("# list: " + root);
if (!Files.exists(root)) {
return;
}
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java Mon Jun 27 17:23:15 2016 +0300
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java Tue Jun 28 19:58:15 2016 +0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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,14 +33,20 @@
import java.util.concurrent.*;
public class CompileTheWorld {
+ // in case when a static constructor changes System::out and System::err
+ // we hold these values of output streams
+ public static final PrintStream OUT = System.out;
+ public static final PrintStream ERR = System.err;
/**
- * Entry point. Compiles classes in {@code args}, or all classes in
- * boot-classpath if args is empty
+ * Entry point. Compiles classes in {@code paths}
*
- * @param args paths to jar/zip, dir contains classes, or to .lst file
- * contains list of classes to compile
+ * @param paths paths to jar/zip, dir contains classes, or to .lst file
+ * contains list of classes to compile
*/
- public static void main(String[] args) {
+ public static void main(String[] paths) {
+ if (paths.length == 0) {
+ throw new IllegalArgumentException("Expect a path to a compile target.");
+ }
String logfile = Utils.LOG_FILE;
PrintStream os = null;
if (logfile != null) {
@@ -62,12 +68,6 @@
} catch (java.lang.NoClassDefFoundError e) {
// compact1, compact2 support
}
- String[] paths = args;
- boolean skipRtJar = false;
- if (args.length == 0) {
- paths = getDefaultPaths();
- skipRtJar = true;
- }
ExecutorService executor = createExecutor();
long start = System.currentTimeMillis();
try {
@@ -75,17 +75,13 @@
for (int i = 0, n = paths.length; i < n
&& !PathHandler.isFinished(); ++i) {
path = paths[i];
- if (skipRtJar && i > 0 && isRtJar(path)) {
- // rt.jar is not first, so skip it
- continue;
- }
PathHandler.create(path, executor).process();
}
} finally {
await(executor);
}
- System.out.printf("Done (%d classes, %d methods, %d ms)%n",
- Compiler.getClassCount(),
+ CompileTheWorld.OUT.printf("Done (%d classes, %d methods, %d ms)%n",
+ PathHandler.getClassCount(),
Compiler.getMethodCount(),
System.currentTimeMillis() - start);
} finally {
@@ -93,6 +89,9 @@
os.close();
}
}
+ // in case when a static constructor creates and runs a new thread
+ // we force it to exit
+ System.exit(0);
}
private static ExecutorService createExecutor() {
@@ -111,13 +110,6 @@
return result;
}
- private static String[] getDefaultPaths() {
- String property = System.getProperty("sun.boot.class.path");
- System.out.println(
- "# use 'sun.boot.class.path' as args: " + property);
- return Utils.PATH_SEPARATOR.split(property);
- }
-
private static void await(ExecutorService executor) {
executor.shutdown();
while (!executor.isTerminated()) {
@@ -130,10 +122,6 @@
}
}
- private static boolean isRtJar(String path) {
- return Utils.endsWithIgnoreCase(path, File.separator + "rt.jar");
- }
-
private static class CurrentThreadExecutor extends AbstractExecutorService {
private boolean isShutdown;
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java Mon Jun 27 17:23:15 2016 +0300
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java Tue Jun 28 19:58:15 2016 +0300
@@ -26,7 +26,6 @@
import sun.hotspot.WhiteBox;
import jdk.internal.misc.SharedSecrets;
import jdk.internal.reflect.ConstantPool;
-
import java.lang.reflect.Executable;
import java.util.Objects;
@@ -38,18 +37,11 @@
* Also contains compiled methods and classes counters.
*/
public class Compiler {
- private Compiler() { }
- private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
- private static final AtomicLong CLASS_COUNT = new AtomicLong(0L);
- private static final AtomicLong METHOD_COUNT = new AtomicLong(0L);
- private static volatile boolean CLASSES_LIMIT_REACHED = false;
- /**
- * @return count of processed classes
- */
- public static long getClassCount() {
- return CLASS_COUNT.get();
- }
+ private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+ private static final AtomicLong METHOD_COUNT = new AtomicLong(0L);
+
+ private Compiler() { }
/**
* @return count of processed methods
@@ -59,58 +51,41 @@
}
/**
- * @return {@code true} if classes limit is reached
- */
- public static boolean isLimitReached() {
- return CLASSES_LIMIT_REACHED;
- }
-
- /**
* Compiles all methods and constructors.
*
* @param aClass class to compile
+ * @param id an id of the class
* @param executor executor used for compile task invocation
* @throws NullPointerException if {@code class} or {@code executor}
* is {@code null}
*/
- public static void compileClass(Class aClass, Executor executor) {
+ public static void compileClass(Class<?> aClass, long id, Executor executor) {
Objects.requireNonNull(aClass);
Objects.requireNonNull(executor);
- long id = CLASS_COUNT.incrementAndGet();
- if (id > Utils.COMPILE_THE_WORLD_STOP_AT) {
- CLASS_COUNT.decrementAndGet();
- CLASSES_LIMIT_REACHED = true;
- return;
- }
+ try {
+ ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
+ getConstantPool(aClass);
+ if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
+ preloadClasses(aClass.getName(), id, constantPool);
+ }
+ long methodCount = 0;
+ for (Executable e : aClass.getDeclaredConstructors()) {
+ ++methodCount;
+ executor.execute(new CompileMethodCommand(id, e));
+ }
+ for (Executable e : aClass.getDeclaredMethods()) {
+ ++methodCount;
+ executor.execute(new CompileMethodCommand(id, e));
+ }
+ METHOD_COUNT.addAndGet(methodCount);
- if (id >= Utils.COMPILE_THE_WORLD_START_AT) {
- String name = aClass.getName();
- try {
- System.out.printf("[%d]\t%s%n", id, name);
- ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
- getConstantPool(aClass);
- if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
- preloadClasses(name, id, constantPool);
- }
- long methodCount = 0;
- for (Executable e : aClass.getDeclaredConstructors()) {
- ++methodCount;
- executor.execute(new CompileMethodCommand(id, name, e));
- }
- for (Executable e : aClass.getDeclaredMethods()) {
- ++methodCount;
- executor.execute(new CompileMethodCommand(id, name, e));
- }
- METHOD_COUNT.addAndGet(methodCount);
-
- if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0
- && (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) {
- WHITE_BOX.deoptimizeAll();
- }
- } catch (Throwable t) {
- System.out.printf("[%d]\t%s\tskipping %s%n", id, name, t);
- t.printStackTrace();
+ if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0
+ && (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) {
+ WHITE_BOX.deoptimizeAll();
}
+ } catch (Throwable t) {
+ CompileTheWorld.OUT.printf("[%d]\t%s\tskipping %s%n", id, aClass.getName(), t);
+ t.printStackTrace();
}
}
@@ -124,8 +99,8 @@
}
}
} catch (Throwable t) {
- System.out.printf("[%d]\t%s\tpreloading failed : %s%n", id,
- className, t);
+ CompileTheWorld.OUT.printf("[%d]\t%s\tpreloading failed : %s%n",
+ id, className, t);
}
}
@@ -142,13 +117,11 @@
/**
* @param classId id of class
- * @param className name of class
* @param method compiled for compilation
*/
- public CompileMethodCommand(long classId, String className,
- Executable method) {
+ public CompileMethodCommand(long classId, Executable method) {
this.classId = classId;
- this.className = className;
+ this.className = method.getDeclaringClass().getName();
this.method = method;
}
@@ -158,10 +131,10 @@
if (Utils.TIERED_COMPILATION) {
for (int i = compLevel; i <= Utils.TIERED_STOP_AT_LEVEL; ++i) {
WHITE_BOX.deoptimizeMethod(method);
- compileMethod(method, i);
+ compileAtLevel(i);
}
} else {
- compileMethod(method, compLevel);
+ compileAtLevel(compLevel);
}
}
@@ -183,29 +156,29 @@
}
}
- private void compileMethod(Executable method, int compLevel) {
+ private void compileAtLevel(int compLevel) {
if (WHITE_BOX.isMethodCompilable(method, compLevel)) {
try {
WHITE_BOX.enqueueMethodForCompilation(method, compLevel);
waitCompilation();
int tmp = WHITE_BOX.getMethodCompilationLevel(method);
if (tmp != compLevel) {
- logMethod(method, "compilation level = " + tmp
+ log("compilation level = " + tmp
+ ", but not " + compLevel);
} else if (Utils.IS_VERBOSE) {
- logMethod(method, "compilation level = " + tmp + ". OK");
+ log("compilation level = " + tmp + ". OK");
}
} catch (Throwable t) {
- logMethod(method, "error on compile at " + compLevel
+ log("error on compile at " + compLevel
+ " level");
t.printStackTrace();
}
} else if (Utils.IS_VERBOSE) {
- logMethod(method, "not compilable at " + compLevel);
+ log("not compilable at " + compLevel);
}
}
- private void logMethod(Executable method, String message) {
+ private void log(String message) {
StringBuilder builder = new StringBuilder("[");
builder.append(classId);
builder.append("]\t");
@@ -226,7 +199,7 @@
builder.append('\t');
builder.append(message);
}
- System.err.println(builder);
+ CompileTheWorld.ERR.println(builder);
}
}
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java Mon Jun 27 17:23:15 2016 +0300
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java Tue Jun 28 19:58:15 2016 +0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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
@@ -23,12 +23,14 @@
package sun.hotspot.tools.ctw;
+import jdk.internal.misc.Unsafe;
+
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.io.File;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.concurrent.Executor;
@@ -38,6 +40,8 @@
* Concrete subclasses should implement method {@link #process()}.
*/
public abstract class PathHandler {
+ private static final AtomicLong CLASS_COUNT = new AtomicLong(0L);
+ private static volatile boolean CLASSES_LIMIT_REACHED = false;
private static final Pattern JAR_IN_DIR_PATTERN
= Pattern.compile("^(.*[/\\\\])?\\*$");
protected final Path root;
@@ -81,6 +85,8 @@
return new ClassPathJarEntry(p, executor);
} else if (isListFile(p)) {
return new ClassesListInFile(p, executor);
+ } else if (isJimageFile(p)) {
+ return new ClassPathJimageEntry(p, executor);
} else {
return new ClassPathDirEntry(p, executor);
}
@@ -96,6 +102,13 @@
return false;
}
+ private static boolean isJimageFile(Path path) {
+ String filename = path.getFileName().toString();
+ return Files.isRegularFile(path)
+ && ("modules".equals(filename)
+ || Utils.endsWithIgnoreCase(filename, ".jimage"));
+ }
+
private static boolean isListFile(Path path) {
if (Files.isRegularFile(path)) {
String name = path.toString();
@@ -122,24 +135,50 @@
}
/**
- * Processes specificed class.
+ * Processes specified class.
* @param name fully qualified name of class to process
*/
protected final void processClass(String name) {
- try {
- Class aClass = Class.forName(name, true, loader);
- Compiler.compileClass(aClass, executor);
- } catch (ClassNotFoundException | LinkageError e) {
- System.out.printf("Class %s loading failed : %s%n", name,
- e.getMessage());
+ Objects.requireNonNull(name);
+ if (CLASSES_LIMIT_REACHED) {
+ return;
+ }
+ long id = CLASS_COUNT.incrementAndGet();
+ if (id > Utils.COMPILE_THE_WORLD_STOP_AT) {
+ CLASSES_LIMIT_REACHED = true;
+ return;
+ }
+ if (id >= Utils.COMPILE_THE_WORLD_START_AT) {
+ try {
+ Class<?> aClass = loader.loadClass(name);
+ CompileTheWorld.OUT.printf("[%d]\t%s%n", id, name);
+ Compiler.compileClass(aClass, id, executor);
+ } catch (ClassNotFoundException e) {
+ CompileTheWorld.OUT.printf("Class %s loading failed : %s%n",
+ name, e.getMessage());
+ }
}
}
/**
- * @return {@code true} if processing should be stopped
+ * @return count of processed classes
+ */
+ public static long getClassCount() {
+ long id = CLASS_COUNT.get();
+ if (id < Utils.COMPILE_THE_WORLD_START_AT) {
+ return 0;
+ }
+ if (id > Utils.COMPILE_THE_WORLD_STOP_AT) {
+ return Utils.COMPILE_THE_WORLD_STOP_AT - Utils.COMPILE_THE_WORLD_START_AT + 1;
+ }
+ return id - Utils.COMPILE_THE_WORLD_START_AT + 1;
+ }
+
+ /**
+ * @return {@code true} if classes limit is reached and processing should be stopped
*/
public static boolean isFinished() {
- return Compiler.isLimitReached();
+ return CLASSES_LIMIT_REACHED;
}
}
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java Mon Jun 27 17:23:15 2016 +0300
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java Tue Jun 28 19:58:15 2016 +0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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
@@ -207,7 +207,12 @@
*/
public static String fileNameToClassName(String filename) {
assert isClassFile(filename);
- return filename.substring(0, filename.length() - CLASSFILE_EXT.length())
- .replace(File.separatorChar, '.');
+ // workaround for the class naming in jimage : /<module>/<class_name>
+ final char nameSeparator = '/';
+ int nameStart = filename.charAt(0) == nameSeparator
+ ? filename.indexOf(nameSeparator, 1) + 1
+ : 0;
+ return filename.substring(nameStart, filename.length() - CLASSFILE_EXT.length())
+ .replace(nameSeparator, '.');
}
}