Thu, 02 Dec 2010 16:37:23 -0800
7004029: intermittent failures compiling pack200
Summary: remove "bogus" entries from star-import scopes
Reviewed-by: mcimadamore
Contributed-by: per.bothner@oracle.com
1 /*
2 * Copyright (c) 2010, 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 */
24 /*
25 * @test
26 * @bug 7004029
27 * @summary Basher for star-import scopes
28 */
30 import java.lang.reflect.*;
31 import java.util.*;
32 import java.util.List;
33 import com.sun.tools.javac.util.*;
34 import com.sun.tools.javac.code.*;
35 import com.sun.tools.javac.code.Scope.*;
36 import com.sun.tools.javac.code.Symbol.*;
37 import com.sun.tools.javac.file.JavacFileManager;
38 import static com.sun.tools.javac.code.Kinds.*;
40 public class StarImportTest {
41 public static void main(String... args) throws Exception {
42 new StarImportTest().run(args);
43 }
45 void run(String... args) throws Exception {
46 int count = 1;
48 for (int i = 0; i < args.length; i++) {
49 String arg = args[i];
50 if (arg.equals("-seed") && (i + 1 < args.length))
51 seed = Long.parseLong(args[++i]);
52 else if(arg.equals("-tests") && (i + 1 < args.length))
53 count = Integer.parseInt(args[++i]);
54 else
55 throw new Exception("unknown arg: " + arg);
56 }
58 rgen = new Random(seed);
60 for (int i = 0; i < count; i++) {
61 Test t = new Test();
62 t.run();
63 }
65 if (errors > 0)
66 throw new Exception(errors + " errors found");
67 }
69 /**
70 * Select a random element from an array of choices.
71 */
72 <T> T random(T... choices) {
73 return choices[rgen.nextInt(choices.length)];
74 }
76 /**
77 * Write a message to stderr.
78 */
79 void log(String msg) {
80 System.err.println(msg);
81 }
83 /**
84 * Write a message to stderr, and dump a scope.
85 */
86 void log(String msg, Scope s) {
87 System.err.print(msg);
88 System.err.print(": ");
89 String sep = "(";
90 for (Scope.Entry se = s.elems; se != null; se = se.sibling) {
91 for (Scope.Entry e = se; e.sym != null; e = e.next()) {
92 System.err.print(sep + e.sym.name + ":" + e.sym);
93 sep = ",";
94 }
95 System.err.print(")");
96 sep = ", (";
97 }
98 System.err.println();
99 }
101 /**
102 * Write an error message to stderr.
103 */
104 void error(String msg) {
105 System.err.println("Error: " + msg);
106 errors++;
107 }
109 Random rgen;
110 long seed = 0;
112 int errors;
114 enum SetupKind { NAMES, PACKAGE, CLASS };
115 static final int MAX_SETUP_COUNT = 50;
116 static final int MAX_SETUP_NAME_COUNT = 20;
117 static final int MAX_SETUP_PACKAGE_COUNT = 20;
118 static final int MAX_SETUP_CLASS_COUNT = 20;
120 /** Class to encapsulate a test run. */
121 class Test {
122 /** Run the test. */
123 void run() throws Exception {
124 log ("starting test");
125 setup();
126 createStarImportScope();
127 test();
128 }
130 /**
131 * Setup env by creating pseudo-random collection of names, packages and classes.
132 */
133 void setup() {
134 log ("setup");
135 context = new Context();
136 JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab
137 names = Names.instance(context); // Name.Table impls tied to an instance of Names
138 symtab = Symtab.instance(context);
139 scopeCounter = ScopeCounter.instance(context);
140 int setupCount = rgen.nextInt(MAX_SETUP_COUNT);
141 for (int i = 0; i < setupCount; i++) {
142 switch (random(SetupKind.values())) {
143 case NAMES:
144 setupNames();
145 break;
146 case PACKAGE:
147 setupPackage();
148 break;
149 case CLASS:
150 setupClass();
151 break;
152 }
153 }
154 }
156 /**
157 * Set up a random number of names.
158 */
159 void setupNames() {
160 int count = rgen.nextInt(MAX_SETUP_NAME_COUNT);
161 log("setup: creating " + count + " new names");
162 for (int i = 0; i < count; i++) {
163 names.fromString("n" + (++nextNameSerial));
164 }
165 }
167 /**
168 * Set up a package containing a random number of member elements.
169 */
170 void setupPackage() {
171 Name name = names.fromString("p" + (++nextPackageSerial));
172 int count = rgen.nextInt(MAX_SETUP_PACKAGE_COUNT);
173 log("setup: creating package " + name + " with " + count + " entries");
174 PackageSymbol p = new PackageSymbol(name, symtab.rootPackage);
175 p.members_field = new Scope(p);
176 for (int i = 0; i < count; i++) {
177 String outer = name + "c" + i;
178 String suffix = random(null, "$Entry", "$Entry2");
179 ClassSymbol c1 = createClass(names.fromString(outer), p);
180 // log("setup: created " + c1);
181 if (suffix != null) {
182 ClassSymbol c2 = createClass(names.fromString(outer + suffix), p);
183 // log("setup: created " + c2);
184 }
185 }
186 // log("package " + p, p.members_field);
187 packages.add(p);
188 imports.add(p);
189 }
191 /**
192 * Set up a class containing a random number of member elements.
193 */
194 void setupClass() {
195 Name name = names.fromString("c" + (++nextClassSerial));
196 int count = rgen.nextInt(MAX_SETUP_CLASS_COUNT);
197 log("setup: creating class " + name + " with " + count + " entries");
198 ClassSymbol c = createClass(name, symtab.unnamedPackage);
199 // log("setup: created " + c);
200 for (int i = 0; i < count; i++) {
201 ClassSymbol ic = createClass(names.fromString("Entry" + i), c);
202 // log("setup: created " + ic);
203 }
204 classes.add(c);
205 imports.add(c);
206 }
208 /**
209 * Create a star-import scope and a model therof, from the packages and
210 * classes created by setupPackages and setupClasses.
211 * @throws Exception for fatal errors, such as from reflection
212 */
213 void createStarImportScope() throws Exception {
214 log ("createStarImportScope");
215 PackageSymbol pkg = new PackageSymbol(names.fromString("pkg"), symtab.rootPackage);
217 // if StarImportScope exists, use it, otherwise, for testing legacy code,
218 // fall back on ImportScope
219 Method importAll;
220 try {
221 Class<?> c = Class.forName("com.sun.tools.javac.code.Scope$StarImportScope");
222 Constructor ctor = c.getDeclaredConstructor(new Class[] { Symbol.class });
223 importAll = c.getDeclaredMethod("importAll", new Class[] { Scope.class });
224 starImportScope = (Scope) ctor.newInstance(new Object[] { pkg });
225 } catch (ClassNotFoundException e) {
226 starImportScope = new ImportScope(pkg);
227 importAll = null;
228 }
229 starImportModel = new Model();
231 for (Symbol imp: imports) {
232 Scope members = imp.members();
233 if (importAll != null) {
234 // log("importAll", members);
235 importAll.invoke(starImportScope, members);
236 } else {
237 Scope fromScope = members;
238 Scope toScope = starImportScope;
239 // The following lines are taken from MemberEnter.importAll,
240 // before the use of StarImportScope.importAll.
241 for (Scope.Entry e = fromScope.elems; e != null; e = e.sibling) {
242 if (e.sym.kind == TYP && !toScope.includes(e.sym))
243 toScope.enter(e.sym, fromScope);
244 }
245 }
247 for (Scope.Entry e = members.elems; e != null; e = e.sibling) {
248 starImportModel.enter(e.sym);
249 }
250 }
252 // log("star-import scope", starImportScope);
253 starImportModel.check(starImportScope);
254 }
256 /**
257 * The core of the test. In a random order, move nested classes from
258 * the package in which they created to the class which should own them.
259 */
260 void test() {
261 log ("test");
262 List<ClassSymbol> nestedClasses = new LinkedList<ClassSymbol>();
263 for (PackageSymbol p: packages) {
264 for (Scope.Entry se = p.members_field.elems; se != null; se = se.sibling) {
265 if (se.sym.name.toString().contains("$"))
266 nestedClasses.add((ClassSymbol) se.sym);
267 }
268 }
270 for (int i = nestedClasses.size(); i > 0; i--) {
271 // select a random nested class to move from package to class
272 ClassSymbol sym = nestedClasses.remove(rgen.nextInt(i));
273 log("adjusting class " + sym);
275 // remove from star import model
276 starImportModel.remove(sym);
278 String s = sym.name.toString();
279 int dollar = s.indexOf("$");
281 // owner should be a package
282 assert (sym.owner.kind == PCK);
284 // determine new owner
285 Name outerName = names.fromString(s.substring(0, dollar));
286 // log(sym + " owner: " + sym.owner, sym.owner.members());
287 Scope.Entry outerEntry = sym.owner.members().lookup(outerName);
288 ClassSymbol outer = (ClassSymbol) outerEntry.sym;
289 // log("outer: " + outerName + " " + outer);
291 // remove from package
292 sym.owner.members().remove(sym);
294 // rename and insert into class
295 sym.name = names.fromString(s.substring(dollar + 1));
296 outer.members().enter(sym);
297 sym.owner = outer;
299 // verify
300 starImportModel.check(starImportScope);
301 }
302 }
304 ClassSymbol createClass(Name name, Symbol owner) {
305 ClassSymbol sym = new ClassSymbol(0, name, owner);
306 sym.members_field = new ClassScope(sym, scopeCounter);
307 if (owner != symtab.unnamedPackage)
308 owner.members().enter(sym);
309 return sym;
310 }
312 Context context;
313 Symtab symtab;
314 ScopeCounter scopeCounter;
315 Names names;
316 int nextNameSerial;
317 List<PackageSymbol> packages = new ArrayList<PackageSymbol>();
318 int nextPackageSerial;
319 List<ClassSymbol> classes = new ArrayList<ClassSymbol>();
320 List<Symbol> imports = new ArrayList<Symbol>();
321 int nextClassSerial;
323 Scope starImportScope;
324 Model starImportModel;
325 }
327 class Model {
328 private Map<Name, Set<Symbol>> map = new HashMap<Name, Set<Symbol>>();
329 private Set<Symbol> bogus = new HashSet<Symbol>();
331 void enter(Symbol sym) {
332 Set<Symbol> syms = map.get(sym.name);
333 if (syms == null)
334 map.put(sym.name, syms = new LinkedHashSet<Symbol>());
335 syms.add(sym);
336 }
338 void remove(Symbol sym) {
339 Set<Symbol> syms = map.get(sym.name);
340 if (syms == null)
341 error("no entries for " + sym.name + " found in reference model");
342 else {
343 boolean ok = syms.remove(sym);
344 if (ok) {
345 // log(sym.name + "(" + sym + ") removed from reference model");
346 } else {
347 error(sym.name + " not found in reference model");
348 }
349 if (syms.isEmpty())
350 map.remove(sym.name);
351 }
352 }
354 /**
355 * Check the contents of a scope
356 */
357 void check(Scope scope) {
358 // First, check all entries in scope are in map
359 int bogusCount = 0;
360 for (Scope.Entry se = scope.elems; se != null; se = se.sibling) {
361 Symbol sym = se.sym;
362 if (sym.owner != se.scope.owner) {
363 if (bogus.contains(sym)) {
364 bogusCount++;
365 } else {
366 log("Warning: " + sym.name + ":" + sym + " appears to be bogus");
367 bogus.add(sym);
368 }
369 } else {
370 Set<Symbol> syms = map.get(sym.name);
371 if (syms == null) {
372 error("check: no entries found for " + sym.name + ":" + sym + " in reference map");
373 } else if (!syms.contains(sym)) {
374 error("check: symbol " + sym.name + ":" + sym + " not found in reference map");
375 }
376 }
377 }
378 if (bogusCount > 0) {
379 log("Warning: " + bogusCount + " other bogus entries previously reported");
380 }
382 // Second, check all entries in map are in scope
383 for (Map.Entry<Name,Set<Symbol>> me: map.entrySet()) {
384 Name name = me.getKey();
385 Scope.Entry se = scope.lookup(name);
386 assert (se != null);
387 if (se.sym == null) {
388 error("check: no entries found for " + name + " in scope");
389 continue;
390 }
391 nextSym:
392 for (Symbol sym: me.getValue()) {
393 for (Scope.Entry e = se; e.sym != null; e = e.next()) {
394 if (sym == e.sym)
395 continue nextSym;
396 }
397 error("check: symbol " + sym + " not found in scope");
398 }
399 }
400 }
401 }
402 }