DupUnsharedTest.java revision 3170:dc017a37aac5
1/* 2 * Copyright (c) 2014, 2015, 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 * @summary WriteableScope.dupUnshared not working properly for shared Scopes. 27 * @modules jdk.compiler/com.sun.tools.javac.code 28 * jdk.compiler/com.sun.tools.javac.file 29 * jdk.compiler/com.sun.tools.javac.util 30 */ 31 32import com.sun.tools.javac.util.*; 33import com.sun.tools.javac.code.*; 34import com.sun.tools.javac.code.Scope.*; 35import com.sun.tools.javac.code.Symbol.*; 36import com.sun.tools.javac.file.JavacFileManager; 37import java.lang.reflect.Field; 38import java.lang.reflect.Method; 39import java.util.Collections; 40import java.util.IdentityHashMap; 41import java.util.Objects; 42import java.util.Set; 43 44public class DupUnsharedTest { 45 public static void main(String... args) throws Exception { 46 new DupUnsharedTest().run(); 47 } 48 49 Context context; 50 Names names; 51 Symtab symtab; 52 Name a; 53 Name b; 54 int errors; 55 56 public DupUnsharedTest() { 57 context = new Context(); 58 JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab 59 names = Names.instance(context); 60 symtab = Symtab.instance(context); 61 a = names.fromString("a"); 62 b = names.fromString("b"); 63 } 64 65 void run() throws Exception { 66 runScopeContentTest(); 67 runClashTest(); 68 69 if (errors > 0) 70 throw new AssertionError("Errors detected (" + errors + ")."); 71 } 72 73 void runScopeContentTest() throws Exception { 74 Set<Symbol> expected = Collections.newSetFromMap(new IdentityHashMap<>() {}); 75 Set<Symbol> notExpected = Collections.newSetFromMap(new IdentityHashMap<>()); 76 WriteableScope s1 = WriteableScope.create(symtab.rootPackage); 77 ClassSymbol acceptSym = symtab.arrayClass; 78 s1.enter(acceptSym); 79 expected.add(acceptSym); 80 WriteableScope s2 = s1.dup(); 81 fillScope(s2, notExpected, a); 82 WriteableScope s3 = s2.dup(); 83 fillScope(s3, notExpected, b); 84 WriteableScope s4 = s1.dupUnshared(); 85 assertEquals(toSet(s4.getSymbols()), expected); 86 assertEquals(toSet(s4.getSymbolsByName(a)), Collections.emptySet()); 87 assertEquals(toSet(s4.getSymbolsByName(b)), Collections.emptySet()); 88 assertEquals(toSet(s4.getSymbolsByName(acceptSym.name)), expected); 89 for (Symbol sym : notExpected) { 90 try { 91 s4.remove(sym); 92 } catch (Exception ex) { 93 System.err.println("s4.remove(" + sym + "); crashes with exception:"); 94 ex.printStackTrace(); 95 errors++; 96 } 97 } 98 } 99 100 void fillScope(WriteableScope scope, Set<Symbol> notExpected, Name name) { 101 VarSymbol var1 = new VarSymbol(0, name, Type.noType, symtab.arrayClass); 102 VarSymbol var2 = new VarSymbol(0, name, Type.noType, symtab.autoCloseableClose.owner); 103 scope.enter(var1); 104 scope.enter(var2); 105 scope.remove(var1); 106 notExpected.add(var1); 107 notExpected.add(var2); 108 } 109 110 Set<Symbol> toSet(Iterable<Symbol> it) { 111 Set<Symbol> result = Collections.newSetFromMap(new IdentityHashMap<>() {}); 112 113 for (Symbol sym : it) { 114 result.add(sym); 115 } 116 117 return result; 118 } 119 120 void assertEquals(Set<Symbol> set1, Set<Symbol> set2) { 121 if (!Objects.equals(set1, set2)) { 122 System.err.println("Sets are not equals: s1=" + set1 + "; s2=" + set2); 123 errors++; 124 } 125 } 126 127 /** 128 * This tests tests the following situation. 129 * - consider empty Scope S1 130 * - a Symbol with name 'A' is added into S1 131 * - S1 is dupped into S2 132 * - a Symbol with name 'B', clashing with 'A', is added into S2 133 * - so the table now looks like: [..., A, ..., B, ...] 134 * - S2 is doubled. As a consequence, the table is re-hashed, and looks like: 135 * [..., B, ..., A, ...] (note that re-hashing goes from the end, hence the original order). 136 * - B has been chosen so that it clashes in the doubled scope as well. So when looking up 'A', 137 * B is found (and rejected) first, and only then the A's bucket is tested. 138 * - S2 is dupUshared - the resulting table needs to look like: [..., /sentinel/, ..., A, ...], not 139 * [..., null, ..., A, ...], as in the latter case lookups would see 'null' while looking for 140 * 'A' and would stop the search prematurely. 141 */ 142 void runClashTest() throws Exception { 143 WriteableScope emptyScope = WriteableScope.create(symtab.unnamedPackage); 144 Field tableField = emptyScope.getClass().getDeclaredField("table"); 145 tableField.setAccessible(true); 146 Method dble = emptyScope.getClass().getDeclaredMethod("dble"); 147 dble.setAccessible(true); 148 Method getIndex = emptyScope.getClass().getDeclaredMethod("getIndex", Name.class); 149 getIndex.setAccessible(true); 150 151 int tries = 0; 152 153 //find a name that will be in the first bucket in table (so that a conflicting name 154 //will be in placed in a bucket after this one). 155 Name first = names.fromString("a"); 156 while ((Integer) getIndex.invoke(emptyScope, first) != 0) { 157 if (tries++ > MAX_TRIES) { 158 System.err.println("could not find a name that would be placed in the first bucket"); 159 errors++; 160 return ; 161 } 162 first = names.fromString("a" + first.toString()); 163 } 164 165 System.out.println("first name: " + first); 166 167 //now, find another name, that will clash with the first one both in the empty and a doubled scope: 168 Scope doubledEmptyScope = WriteableScope.create(symtab.unnamedPackage); 169 dble.invoke(doubledEmptyScope); 170 Integer firstNameTestScopeIndex = (Integer) getIndex.invoke(emptyScope, first); 171 Integer firstNameDoubleScopeIndex = (Integer) getIndex.invoke(doubledEmptyScope, first); 172 Name other = names.fromString("b"); 173 while (!Objects.equals(firstNameTestScopeIndex, getIndex.invoke(emptyScope, other)) || 174 !Objects.equals(firstNameDoubleScopeIndex, getIndex.invoke(doubledEmptyScope, other))) { 175 if (tries++ > MAX_TRIES) { 176 System.err.println("could not find a name that would properly clash with the first chosen name"); 177 errors++; 178 return ; 179 } 180 other = names.fromString("b" + other); 181 } 182 183 System.out.println("other name: " + other); 184 185 Symbol firstSymbol = new VarSymbol(0, first, Type.noType, null); 186 Symbol otherSymbol = new VarSymbol(0, other, Type.noType, null); 187 188 //test the situation described above: 189 WriteableScope testScope1 = WriteableScope.create(symtab.unnamedPackage); 190 testScope1.enter(firstSymbol); 191 192 WriteableScope dupped1 = testScope1.dup(); 193 194 dupped1.enter(otherSymbol); 195 dble.invoke(dupped1); 196 197 if (testScope1.dupUnshared().findFirst(first) != firstSymbol) { 198 System.err.println("cannot find the Symbol in the dupUnshared scope (1)"); 199 errors++; 200 } 201 202 //also check a situation where the clashing Symbol is removed from the dupped scope: 203 WriteableScope testScope2 = WriteableScope.create(symtab.unnamedPackage); 204 testScope2.enter(firstSymbol); 205 206 WriteableScope dupped2 = testScope2.dup(); 207 208 dupped2.enter(otherSymbol); 209 dble.invoke(dupped2); 210 dupped2.remove(otherSymbol); 211 212 if (testScope2.dupUnshared().findFirst(first) != firstSymbol) { 213 System.err.println("cannot find the Symbol in the dupUnshared scope (2)"); 214 errors++; 215 } 216 } 217 218 int MAX_TRIES = 100; // max tries to find a hash clash before giving up. 219 220} 221