1 /*
2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /**
25  * @test
26  * @bug 8193717
27  * @summary Check that code with a lot named imports can compile.
28  * @library /tools/lib
29  * @modules jdk.jdeps/com.sun.tools.classfile
30  *          jdk.compiler/com.sun.tools.javac.api
31  *          jdk.compiler/com.sun.tools.javac.main
32  *          jdk.jdeps/com.sun.tools.javap
33  * @build toolbox.ToolBox toolbox.JavapTask
34  * @run main T8193717
35  */
36 
37 import java.io.ByteArrayInputStream;
38 import java.io.ByteArrayOutputStream;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.net.URI;
42 import java.net.URISyntaxException;
43 import java.nio.file.Paths;
44 import java.util.ArrayList;
45 import java.util.List;
46 import java.util.Set;
47 
48 import javax.tools.ForwardingJavaFileManager;
49 import javax.tools.JavaCompiler;
50 import javax.tools.JavaFileManager;
51 import javax.tools.JavaFileObject;
52 import javax.tools.JavaFileObject.Kind;
53 import javax.tools.SimpleJavaFileObject;
54 import javax.tools.StandardJavaFileManager;
55 import javax.tools.StandardLocation;
56 import javax.tools.ToolProvider;
57 
58 import com.sun.tools.classfile.AccessFlags;
59 import com.sun.tools.classfile.Attribute;
60 import com.sun.tools.classfile.Attributes;
61 import com.sun.tools.classfile.ClassFile;
62 import com.sun.tools.classfile.ClassWriter;
63 import com.sun.tools.classfile.ConstantPool;
64 import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
65 import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info;
66 import com.sun.tools.classfile.ConstantPool.CPInfo;
67 import com.sun.tools.classfile.Field;
68 import com.sun.tools.classfile.Method;
69 
70 import toolbox.JavacTask;
71 import toolbox.ToolBox;
72 
73 public class T8193717 {
main(String... args)74     public static void main(String... args) throws IOException {
75         new T8193717().run();
76     }
77 
78     private static final int CLASSES = 500000;
79 
run()80     private void run() throws IOException {
81         StringBuilder imports = new StringBuilder();
82         StringBuilder use = new StringBuilder();
83 
84         for (int c = 0; c < CLASSES; c++) {
85             String simpleName = getSimpleName(c);
86             String pack = "p";
87             imports.append("import " + pack + "." + simpleName + ";\n");
88             use.append(simpleName + " " + simpleName + ";\n");
89         }
90         String source = imports.toString() + "public class T {\n" + use.toString() + "}";
91         ToolBox tb = new ToolBox();
92         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
93 
94         try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
95             fm.setLocationFromPaths(StandardLocation.CLASS_OUTPUT, List.of(Paths.get(".")));
96             new JavacTask(tb).sources(source)
97                              .options("-XDshould-stop.at=ATTR") //the source is too big for a classfile
98                              .fileManager(new TestJFM(fm))
99                              .run();
100         }
101     }
102 
getSimpleName(int c)103     private static String getSimpleName(int c) {
104         return "T" + String.format("%0" + (int) Math.ceil(Math.log10(CLASSES)) + "d", c);
105     }
106 
generateClassFile(String name)107     private byte[] generateClassFile(String name) throws IOException {
108         ConstantPool cp = new ConstantPool(new CPInfo[] {
109             new CONSTANT_Utf8_info(""),                     //0
110             new CONSTANT_Utf8_info(name.replace(".", "/")), //1
111             new CONSTANT_Class_info(null, 1),               //2
112             new CONSTANT_Utf8_info("java/lang/Object"),     //3
113             new CONSTANT_Class_info(null, 3),               //4
114         });
115         ClassFile cf = new ClassFile(0xCAFEBABE,
116                       0,
117                       51,
118                       cp,
119                       new AccessFlags(AccessFlags.ACC_ABSTRACT |
120                                       AccessFlags.ACC_INTERFACE |
121                                       AccessFlags.ACC_PUBLIC),
122                       2,
123                       4,
124                       new int[0],
125                       new Field[0],
126                       new Method[0],
127                       new Attributes(cp, new Attribute[0]));
128         ByteArrayOutputStream baos = new ByteArrayOutputStream();
129         new ClassWriter().write(cf, baos);
130         return baos.toByteArray();
131     }
132 
133     final class TestJFM extends ForwardingJavaFileManager<JavaFileManager> {
134 
TestJFM(JavaFileManager fileManager)135         public TestJFM(JavaFileManager fileManager) {
136             super(fileManager);
137         }
138 
139         @Override
list(Location location, String packageName, Set<Kind> kinds, boolean recurse)140         public Iterable<JavaFileObject> list(Location location, String packageName,
141                                              Set<Kind> kinds, boolean recurse) throws IOException {
142             if (location == StandardLocation.CLASS_PATH) {
143                 if (packageName.equals("p")) {
144                     try {
145                         List<JavaFileObject> result = new ArrayList<>(CLASSES);
146 
147                         for (int c = 0; c < CLASSES; c++) {
148                             result.add(new TestJFO("p." + getSimpleName(c)));
149                         }
150 
151                         return result;
152                     } catch (URISyntaxException ex) {
153                         throw new IllegalStateException(ex);
154                     }
155                 }
156             }
157             return super.list(location, packageName, kinds, recurse);
158         }
159 
160         @Override
inferBinaryName(Location location, JavaFileObject file)161         public String inferBinaryName(Location location, JavaFileObject file) {
162             if (file instanceof TestJFO) {
163                 return ((TestJFO) file).name;
164             }
165             return super.inferBinaryName(location, file);
166         }
167 
168         private class TestJFO extends SimpleJavaFileObject {
169 
170             private final String name;
171 
TestJFO(String name)172             public TestJFO(String name) throws URISyntaxException {
173                 super(new URI("mem://" + name.replace(".", "/") + ".class"), Kind.CLASS);
174                 this.name = name;
175             }
176 
177             @Override
openInputStream()178             public InputStream openInputStream() throws IOException {
179                 return new ByteArrayInputStream(generateClassFile(name));
180             }
181         }
182 
183     }
184 }
185