cfdc64fcb4
Reviewed-by: liach, redestad, vromero
183 lines
6.5 KiB
Java
183 lines
6.5 KiB
Java
/*
|
|
* Copyright (c) 2022, 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.
|
|
*/
|
|
|
|
/*
|
|
* @test
|
|
* @bug 8280067
|
|
* @summary Verify constant/immediate char values are correctly enhanced to ints when used in unary
|
|
* operators
|
|
* @library /tools/lib
|
|
* @enablePreview
|
|
* @modules jdk.compiler/com.sun.tools.javac.api
|
|
* jdk.compiler/com.sun.tools.javac.code
|
|
* jdk.compiler/com.sun.tools.javac.comp
|
|
* jdk.compiler/com.sun.tools.javac.jvm
|
|
* jdk.compiler/com.sun.tools.javac.main
|
|
* jdk.compiler/com.sun.tools.javac.tree
|
|
* jdk.compiler/com.sun.tools.javac.util
|
|
* java.base/jdk.internal.classfile.impl
|
|
* jdk.jdeps/com.sun.tools.javap
|
|
* @build toolbox.JarTask toolbox.JavacTask toolbox.JavapTask toolbox.ToolBox
|
|
* @compile CharImmediateValue.java
|
|
* @run main CharImmediateValue
|
|
*/
|
|
|
|
import java.net.URL;
|
|
import java.net.URLClassLoader;
|
|
import java.nio.file.DirectoryStream;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.util.Objects;
|
|
|
|
import com.sun.source.util.JavacTask;
|
|
import com.sun.source.util.Plugin;
|
|
import com.sun.source.util.TaskEvent;
|
|
import com.sun.source.util.TaskListener;
|
|
|
|
import java.lang.classfile.*;
|
|
import java.lang.classfile.attribute.CodeAttribute;
|
|
|
|
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
|
|
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
|
import com.sun.tools.javac.tree.TreeScanner;
|
|
|
|
import toolbox.JarTask;
|
|
import toolbox.ToolBox;
|
|
|
|
|
|
public class CharImmediateValue implements Plugin {
|
|
public static void main(String... args) throws Exception {
|
|
new CharImmediateValue().runSourceTest();
|
|
new CharImmediateValue().runReplacementTest();
|
|
}
|
|
|
|
void runSourceTest() throws Exception {
|
|
int param = 0;
|
|
Character var = (char) -(false ? (char) param : (char) 2);
|
|
}
|
|
|
|
void runReplacementTest() throws Exception {
|
|
ToolBox tb = new ToolBox();
|
|
Path pluginClasses = Path.of("plugin-classes");
|
|
tb.writeFile(pluginClasses.resolve("META-INF").resolve("services").resolve(Plugin.class.getName()),
|
|
CharImmediateValue.class.getName() + System.lineSeparator());
|
|
try (DirectoryStream<Path> ds = Files.newDirectoryStream(Path.of(ToolBox.testClasses))) {
|
|
for (Path p : ds) {
|
|
if (p.getFileName().toString().startsWith("CharImmediateValue") ||
|
|
p.getFileName().toString().endsWith(".class")) {
|
|
Files.copy(p, pluginClasses.resolve(p.getFileName()));
|
|
}
|
|
}
|
|
}
|
|
|
|
Path pluginJar = Path.of("plugin.jar");
|
|
new JarTask(tb, pluginJar)
|
|
.baseDir(pluginClasses)
|
|
.files(".")
|
|
.run();
|
|
|
|
Path src = Path.of("src");
|
|
tb.writeJavaFiles(src,
|
|
"""
|
|
public class Test{
|
|
private static char replace; //this will be replace with a constant "1" after constant folding is done
|
|
public static String run() {
|
|
char c = (char) - replace;
|
|
if (c < 0) {
|
|
throw new AssertionError("Incorrect value!");
|
|
} else {
|
|
return Integer.toString(c);
|
|
}
|
|
}
|
|
}
|
|
""");
|
|
Path classes = Files.createDirectories(Path.of("classes"));
|
|
|
|
new toolbox.JavacTask(tb)
|
|
.classpath(pluginJar)
|
|
.options("-XDaccessInternalAPI")
|
|
.outdir(classes)
|
|
.files(tb.findJavaFiles(src))
|
|
.run()
|
|
.writeAll();
|
|
|
|
URLClassLoader cl = new URLClassLoader(new URL[] {classes.toUri().toURL()});
|
|
|
|
String actual = (String) cl.loadClass("Test")
|
|
.getMethod("run")
|
|
.invoke(null);
|
|
String expected = "65535";
|
|
if (!Objects.equals(actual, expected)) {
|
|
throw new AssertionError("expected: " + expected + "; but got: " + actual);
|
|
}
|
|
|
|
Path testClass = classes.resolve("Test.class");
|
|
ClassModel cf = ClassFile.of().parse(testClass);
|
|
CodeAttribute codeAttr = cf.methods().get(1).findAttribute(Attributes.code()).orElseThrow();
|
|
boolean seenCast = false;
|
|
for (CodeElement i : codeAttr.elementList()) {
|
|
if (i instanceof Instruction ins && ins.opcode() == Opcode.I2C) {
|
|
seenCast = true;
|
|
}
|
|
}
|
|
if (!seenCast) {
|
|
throw new AssertionError("Missing cast!");
|
|
}
|
|
}
|
|
|
|
// Plugin impl...
|
|
|
|
@Override
|
|
public String getName() { return "CharImmediateValue"; }
|
|
|
|
@Override
|
|
public void init(JavacTask task, String... args) {
|
|
task.addTaskListener(new TaskListener() {
|
|
@Override
|
|
public void started(TaskEvent e) {
|
|
if (e.getKind() == TaskEvent.Kind.GENERATE) {
|
|
convert((JCCompilationUnit) e.getCompilationUnit());
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public boolean autoStart() {
|
|
return true;
|
|
}
|
|
|
|
private void convert(JCCompilationUnit toplevel) {
|
|
new TreeScanner() {
|
|
@Override
|
|
public void visitIdent(JCIdent tree) {
|
|
if (tree.name.contentEquals("replace")) {
|
|
tree.type = tree.type.constType(1);
|
|
}
|
|
super.visitIdent(tree);
|
|
}
|
|
}.scan(toplevel);
|
|
}
|
|
|
|
}
|