1 /* 2 * Copyright (c) 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 package jdk.test.lib.jittester.factories; 25 26 import java.util.ArrayList; 27 import java.util.HashSet; 28 import java.util.Iterator; 29 import java.util.LinkedList; 30 import jdk.test.lib.jittester.IRNode; 31 import jdk.test.lib.jittester.ProductionFailedException; 32 import jdk.test.lib.jittester.ProductionParams; 33 import jdk.test.lib.jittester.Symbol; 34 import jdk.test.lib.jittester.SymbolTable; 35 import jdk.test.lib.jittester.Type; 36 import jdk.test.lib.jittester.TypeList; 37 import jdk.test.lib.jittester.VariableInfo; 38 import jdk.test.lib.jittester.classes.Klass; 39 import jdk.test.lib.jittester.functions.FunctionDeclarationBlock; 40 import jdk.test.lib.jittester.functions.FunctionDefinition; 41 import jdk.test.lib.jittester.functions.FunctionInfo; 42 import jdk.test.lib.jittester.types.TypeKlass; 43 import jdk.test.lib.jittester.utils.PseudoRandom; 44 45 class KlassFactory extends Factory<Klass> { 46 private final String name; 47 private final long complexityLimit; 48 private final int statementsInFunctionLimit; 49 private final int operatorLimit; 50 private final int memberFunctionsArgLimit; 51 private final int level; 52 private final ArrayList<TypeKlass> interfaces; 53 private TypeKlass thisKlass; 54 private TypeKlass parent; 55 private int memberFunctionsLimit; 56 57 KlassFactory(String name, long complexityLimit, 58 int memberFunctionsLimit, int memberFunctionsArgLimit, int statementsInFunctionLimit, 59 int operatorLimit, int level) { 60 this.name = name; 61 this.complexityLimit = complexityLimit; 62 this.memberFunctionsLimit = memberFunctionsLimit; 63 this.memberFunctionsArgLimit = memberFunctionsArgLimit; 64 this.statementsInFunctionLimit = statementsInFunctionLimit; 65 this.operatorLimit = operatorLimit; 66 this.level = level; 67 interfaces = new ArrayList<>(); 68 } 69 70 @Override 71 public Klass produce() throws ProductionFailedException { 72 HashSet<Symbol> abstractSet = new HashSet<>(); 73 HashSet<Symbol> overrideSet = new HashSet<>(); 74 thisKlass = new TypeKlass(name); 75 // Do we want to inherit something? 76 if (!ProductionParams.disableInheritance.value()) { 77 inheritClass(); 78 inheritInterfaces(); 79 // Now, we should carefully construct a set of all methods with are still abstract. 80 // In order to do that, we will make two sets of methods: abstract and non-abstract. 81 // Then by substracting non-abstract from abstract we'll get what we want. 82 HashSet<Symbol> nonAbstractSet = new HashSet<>(); 83 for (Symbol symbol : SymbolTable.getAllCombined(thisKlass, FunctionInfo.class)) { 84 FunctionInfo functionInfo = (FunctionInfo) symbol; 85 // There could be multiple definitions or declarations encountered, 86 // but all we interested in are signatures. 87 if ((functionInfo.flags & FunctionInfo.ABSTRACT) > 0) { 88 abstractSet.add(functionInfo); 89 } else { 90 nonAbstractSet.add(functionInfo); 91 } 92 } 93 abstractSet.removeAll(nonAbstractSet); 94 // We may randomly remove some elements from the abstract set in order to force generation 95 // of an abstract class. 96 if (PseudoRandom.randomBoolean(0.2)) { 97 // so, we want to be abstract.. 98 for (Iterator<Symbol> i = abstractSet.iterator(); i.hasNext();) { 99 i.next(); 100 if (PseudoRandom.randomBoolean(0.2)) { 101 thisKlass.setAbstract(); 102 i.remove(); 103 } 104 } 105 } 106 if (PseudoRandom.randomBoolean(0.2)) { 107 int redefineLimit = (int) (memberFunctionsLimit * PseudoRandom.random()); 108 if (redefineLimit > 0) { 109 // We may also select some functions from the hierarchy that we want 110 // to redefine.. 111 int i = 0; 112 ArrayList<Symbol> shuffledNonAbstractSet = new ArrayList<>(nonAbstractSet); 113 PseudoRandom.shuffle(shuffledNonAbstractSet); 114 for (Symbol symbol : shuffledNonAbstractSet) { 115 if (++i > redefineLimit) { 116 break; 117 } 118 FunctionInfo functionInfo = (FunctionInfo) symbol; 119 if ((functionInfo.flags & FunctionInfo.FINAL) > 0) { 120 continue; 121 } 122 overrideSet.add(functionInfo); 123 } 124 } 125 } 126 memberFunctionsLimit -= abstractSet.size() + overrideSet.size(); 127 // Ok, remove the symbols from the table which are going to be overrided. 128 // Because the redefiner would probably modify them and put them back into table. 129 for (Symbol symbol : abstractSet) { 130 SymbolTable.remove(symbol); 131 } 132 for (Symbol symbol : overrideSet) { 133 SymbolTable.remove(symbol); 134 } 135 } else { 136 parent = TypeList.OBJECT; 137 thisKlass.addParent(parent.getName()); 138 thisKlass.setParent(parent); 139 parent.addChild(name); 140 } 141 SymbolTable.add(new VariableInfo("this", thisKlass, thisKlass, 142 VariableInfo.FINAL | VariableInfo.LOCAL | VariableInfo.INITIALIZED)); 143 IRNode variableDeclarations = null; 144 IRNode constructorDefinitions = null; 145 IRNode functionDefinitions = null; 146 IRNode functionDeclarations = null; 147 IRNode abstractFunctionsRedefinitions = null; 148 IRNode overridenFunctionsRedefinitions = null; 149 IRNodeBuilder builder = new IRNodeBuilder().setOwnerKlass(thisKlass) 150 .setExceptionSafe(true); 151 try { 152 builder.setLevel(level + 1) 153 .setOperatorLimit(operatorLimit) 154 .setStatementLimit(statementsInFunctionLimit) 155 .setMemberFunctionsArgLimit(memberFunctionsArgLimit); 156 variableDeclarations = builder.setComplexityLimit((long) (complexityLimit * 0.001 * PseudoRandom.random())) 157 .getVariableDeclarationBlockFactory().produce(); 158 if (!ProductionParams.disableFunctions.value()) { 159 // Try to implement all methods. 160 abstractFunctionsRedefinitions = builder.setComplexityLimit((long) (complexityLimit * 0.3 * PseudoRandom.random())) 161 .setLevel(level + 1) 162 .getFunctionRedefinitionBlockFactory(abstractSet) 163 .produce(); 164 overridenFunctionsRedefinitions = builder.setComplexityLimit((long) (complexityLimit * 0.3 * PseudoRandom.random())) 165 .getFunctionRedefinitionBlockFactory(overrideSet) 166 .produce(); 167 if (PseudoRandom.randomBoolean(0.2)) { // wanna be abstract ? 168 functionDeclarations = builder.setMemberFunctionsLimit((int) (memberFunctionsLimit * 0.2 169 * PseudoRandom.random())) 170 .getFunctionDeclarationBlockFactory() 171 .produce(); 172 if (((FunctionDeclarationBlock) functionDeclarations).size() > 0) { 173 thisKlass.setAbstract(); 174 } 175 } 176 functionDefinitions = builder.setComplexityLimit((long) (complexityLimit * 0.5 * PseudoRandom.random())) 177 .setMemberFunctionsLimit((int) (memberFunctionsLimit * 0.6 178 * PseudoRandom.random())) 179 .setFlags(FunctionInfo.NONE) 180 .getFunctionDefinitionBlockFactory() 181 .produce(); 182 constructorDefinitions = builder.setComplexityLimit((long) (complexityLimit * 0.2 * PseudoRandom.random())) 183 .setMemberFunctionsLimit((int) (memberFunctionsLimit * 0.2 184 * PseudoRandom.random())) 185 .setStatementLimit(statementsInFunctionLimit) 186 .setOperatorLimit(operatorLimit) 187 .setLevel(level + 1) 188 .getConstructorDefinitionBlockFactory() 189 .produce(); 190 } 191 } catch (ProductionFailedException e) { 192 System.out.println("Exception during klass production process:"); 193 e.printStackTrace(System.out); 194 throw e; 195 } finally { 196 SymbolTable.remove(new Symbol("this", thisKlass, thisKlass, VariableInfo.NONE)); 197 } 198 // a non-abstract class can be final, so we should allow this to happen. 199 if (!ProductionParams.disableFinalClasses.value() && !thisKlass.isAbstract() 200 && PseudoRandom.randomBoolean()) { 201 thisKlass.setFinal(); 202 } 203 TypeList.add(thisKlass); 204 IRNode printVariables = builder.setLevel(2).getPrintVariablesFactory().produce(); 205 return new Klass(thisKlass, parent, interfaces, name, level, 206 variableDeclarations, constructorDefinitions, functionDefinitions, 207 abstractFunctionsRedefinitions, overridenFunctionsRedefinitions, 208 functionDeclarations, printVariables); 209 } 210 211 private void inheritClass() { 212 // Grab all Klasses from the TypeList and select one to be a parent 213 LinkedList<Type> probableParents = new LinkedList<>(TypeList.getAll()); 214 for (Iterator<Type> i = probableParents.iterator(); i.hasNext();) { 215 Type klass = i.next(); 216 if (!(klass instanceof TypeKlass) || ((TypeKlass) klass).isFinal() 217 || ((TypeKlass) klass).isInterface()) { 218 // we can not derive from finals and interfaces 219 i.remove(); 220 } 221 } 222 if (probableParents.isEmpty()) { 223 parent = TypeList.OBJECT; 224 } else { 225 parent = (TypeKlass) PseudoRandom.randomElement(probableParents); 226 } 227 thisKlass.addParent(parent.getName()); 228 thisKlass.setParent(parent); 229 parent.addChild(name); 230 for (Symbol symbol : SymbolTable.getAllCombined(parent)) { 231 if ((symbol.flags & Symbol.PRIVATE) == 0) { 232 Symbol symbolCopy = symbol.deepCopy(); 233 if (symbolCopy instanceof FunctionInfo) { 234 FunctionInfo functionInfo = (FunctionInfo) symbolCopy; 235 if (functionInfo.isConstructor()) { 236 continue; 237 } 238 if ((functionInfo.flags & FunctionInfo.STATIC) == 0) { 239 functionInfo.argTypes.get(0).type = thisKlass; 240 } 241 } 242 symbolCopy.owner = thisKlass; 243 SymbolTable.add(symbolCopy); 244 } 245 } 246 } 247 248 private void inheritInterfaces() { 249 // Select interfaces that we'll implement. 250 LinkedList<Type> probableInterfaces = new LinkedList<>(TypeList.getAll()); 251 for (Iterator<Type> i = probableInterfaces.iterator(); i.hasNext();) { 252 Type klass = i.next(); 253 if (!(klass instanceof TypeKlass) || !((TypeKlass) klass).isInterface()) { 254 i.remove(); 255 } 256 } 257 PseudoRandom.shuffle(probableInterfaces); 258 int implLimit = (int) (ProductionParams.implementationLimit.value() * PseudoRandom.random()); 259 // Mulitiple inheritance compatibility check 260 compatibility_check: 261 for (Iterator<Type> i = probableInterfaces.iterator(); i.hasNext() && implLimit > 0; implLimit--) { 262 TypeKlass iface = (TypeKlass) i.next(); 263 ArrayList<Symbol> ifaceFuncSet = SymbolTable.getAllCombined(iface, FunctionInfo.class); 264 for (Symbol symbol : SymbolTable.getAllCombined(thisKlass, FunctionInfo.class)) { 265 if (FunctionDefinition.isInvalidOverride((FunctionInfo) symbol, ifaceFuncSet)) { 266 continue compatibility_check; 267 } 268 } 269 interfaces.add(iface); 270 iface.addChild(name); 271 thisKlass.addParent(iface.getName()); 272 for (Symbol symbol : SymbolTable.getAllCombined(iface, FunctionInfo.class)) { 273 FunctionInfo functionInfo = (FunctionInfo) symbol.deepCopy(); 274 functionInfo.owner = thisKlass; 275 functionInfo.argTypes.get(0).type = thisKlass; 276 SymbolTable.add(functionInfo); 277 } 278 } 279 } 280 }