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.List; 29 import jdk.test.lib.jittester.BuiltInType; 30 import jdk.test.lib.jittester.IRNode; 31 import jdk.test.lib.jittester.Literal; 32 import jdk.test.lib.jittester.Nothing; 33 import jdk.test.lib.jittester.ProductionFailedException; 34 import jdk.test.lib.jittester.Rule; 35 import jdk.test.lib.jittester.Switch; 36 import jdk.test.lib.jittester.Type; 37 import jdk.test.lib.jittester.TypeUtil; 38 import jdk.test.lib.jittester.types.TypeKlass; 39 import jdk.test.lib.jittester.types.TypeByte; 40 import jdk.test.lib.jittester.types.TypeChar; 41 import jdk.test.lib.jittester.types.TypeInt; 42 import jdk.test.lib.jittester.types.TypeShort; 43 import jdk.test.lib.jittester.utils.PseudoRandom; 44 45 class SwitchFactory extends SafeFactory { 46 private int caseBlockIdx; 47 protected long complexityLimit; 48 protected int statementLimit, operatorLimit; 49 private boolean canHaveReturn = false; 50 private final TypeKlass ownerClass; 51 private final int level; 52 53 SwitchFactory(TypeKlass ownerClass, long complexityLimit, int statementLimit, 54 int operatorLimit, int level, boolean canHaveReturn) { 55 this.ownerClass = ownerClass; 56 this.complexityLimit = complexityLimit; 57 this.statementLimit = statementLimit; 58 this.operatorLimit = operatorLimit; 59 this.level = level; 60 this.canHaveReturn = canHaveReturn; 61 } 62 63 @Override 64 protected IRNode sproduce() throws ProductionFailedException { 65 if (statementLimit > 0 && complexityLimit > 0) { 66 ArrayList<Type> switchTypes = new ArrayList<>(); 67 switchTypes.add(new TypeChar()); 68 switchTypes.add(new TypeByte()); 69 switchTypes.add(new TypeShort()); 70 switchTypes.add(new TypeInt()); 71 PseudoRandom.shuffle(switchTypes); 72 IRNodeBuilder builder = new IRNodeBuilder() 73 .setOwnerKlass(ownerClass) 74 .setOperatorLimit(operatorLimit) 75 .setSubBlock(false) 76 .setCanHaveBreaks(true) 77 .setCanHaveContinues(false) 78 .setCanHaveReturn(canHaveReturn); 79 MAIN_LOOP: 80 for (Type type : switchTypes) { 81 ArrayList<IRNode> caseConsts = new ArrayList<>(); 82 ArrayList<IRNode> caseBlocks = new ArrayList<>(); 83 try { 84 int accumulatedStatements = 0; 85 int currentStatementsLimit = 0; 86 long accumulatedComplexity = 0L; 87 long currentComplexityLimit = 0L; 88 currentComplexityLimit = (long) (PseudoRandom.random() 89 * (complexityLimit - accumulatedComplexity)); 90 IRNode switchExp = builder.setComplexityLimit(currentComplexityLimit) 91 .setResultType(type) 92 .setExceptionSafe(false) 93 .setNoConsts(true) 94 .getLimitedExpressionFactory() 95 .produce(); 96 accumulatedComplexity += currentComplexityLimit; 97 ArrayList<Type> caseTypes = new ArrayList<>(); 98 caseTypes.add(new TypeByte()); 99 caseTypes.add(new TypeChar()); 100 caseTypes = new ArrayList<>(TypeUtil.getLessCapatiousOrEqualThan(caseTypes, 101 (BuiltInType) type)); 102 if (PseudoRandom.randomBoolean()) { // "default" 103 currentStatementsLimit = (int) (PseudoRandom.random() 104 * (statementLimit - accumulatedStatements)); 105 currentComplexityLimit = (long) (PseudoRandom.random() 106 * (complexityLimit - accumulatedComplexity)); 107 caseConsts.add(null); 108 caseBlocks.add(builder.setComplexityLimit(currentComplexityLimit) 109 .setStatementLimit(currentStatementsLimit) 110 .setLevel(level + 1) 111 .setCanHaveReturn(false) 112 .setCanHaveBreaks(false) 113 .getBlockFactory() 114 .produce()); 115 builder.setCanHaveBreaks(true) 116 .setCanHaveReturn(canHaveReturn); 117 accumulatedStatements += currentStatementsLimit; 118 accumulatedComplexity += currentComplexityLimit; 119 } 120 HashSet<Integer> cases = new HashSet<>(); 121 while (accumulatedStatements < statementLimit) { // "case"s 122 currentStatementsLimit = (int) (PseudoRandom.random() 123 * (statementLimit - accumulatedStatements)); 124 currentComplexityLimit = (long) (PseudoRandom.random() 125 * (complexityLimit - accumulatedComplexity)); 126 PseudoRandom.shuffle(caseTypes); 127 for (int tryCount = 0; true; tryCount++) { 128 if (tryCount >= 10) { 129 continue MAIN_LOOP; 130 } 131 Literal literal = (Literal) builder.setResultType(caseTypes.get(0)) 132 .getLiteralFactory().produce(); 133 int value = 0; 134 if (literal.value instanceof Integer) { 135 value = (Integer) literal.value; 136 } 137 if (literal.value instanceof Short) { 138 value = (Short) literal.value; 139 } 140 if (literal.value instanceof Byte) { 141 value = (Byte) literal.value; 142 } 143 if (literal.value instanceof Character) { 144 value = (Character) literal.value; 145 } 146 if (!cases.contains(value)) { 147 cases.add(value); 148 caseConsts.add(literal); 149 break; 150 } 151 } 152 Rule rule = new Rule("case_block"); 153 rule.add("block", builder.setComplexityLimit(currentComplexityLimit) 154 .setStatementLimit(currentStatementsLimit) 155 .setLevel(level) 156 .setCanHaveReturn(false) 157 .setCanHaveBreaks(false) 158 .getBlockFactory()); 159 builder.setCanHaveBreaks(true) 160 .setCanHaveReturn(canHaveReturn); 161 rule.add("nothing", builder.getNothingFactory()); 162 IRNode choiceResult = rule.produce(); 163 caseBlocks.add(choiceResult); 164 if (choiceResult instanceof Nothing) { 165 accumulatedStatements++; 166 } else { 167 accumulatedStatements += currentStatementsLimit; 168 accumulatedComplexity += currentComplexityLimit; 169 } 170 } 171 PseudoRandom.shuffle(caseConsts); 172 List<IRNode> accum = new ArrayList<>(); 173 caseBlockIdx = 1 + caseConsts.size(); 174 accum.add(switchExp); 175 for (int i = 1; i < caseBlockIdx; ++i) { 176 accum.add(caseConsts.get(i - 1)); 177 } 178 for (int i = caseBlockIdx; i < 1 + caseConsts.size() + caseBlocks.size(); ++i) { 179 accum.add(caseBlocks.get(i - caseBlockIdx)); 180 } 181 return new Switch(level, accum, caseBlockIdx); 182 } catch (ProductionFailedException e) { 183 } 184 } 185 } 186 throw new ProductionFailedException(); 187 } 188 }