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 }