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.List;
  28 import jdk.test.lib.jittester.CatchBlock;
  29 import jdk.test.lib.jittester.IRNode;
  30 import jdk.test.lib.jittester.ProductionFailedException;
  31 import jdk.test.lib.jittester.TryCatchBlock;
  32 import jdk.test.lib.jittester.Type;
  33 import jdk.test.lib.jittester.TypeList;
  34 import jdk.test.lib.jittester.utils.TypeUtil;
  35 import jdk.test.lib.jittester.types.TypeKlass;
  36 import jdk.test.lib.jittester.utils.PseudoRandom;
  37 
  38 class TryCatchBlockFactory extends Factory {
  39     private final static double CATCH_SELECTION_COEF = 0.1d;
  40     private final Type returnType;
  41     private final long complexityLimit;
  42     private final int statementLimit, operatorLimit;
  43     private final boolean subBlock;
  44     private final boolean canHaveBreaks;
  45     private final boolean canHaveContinues;
  46     private final boolean canHaveReturn;
  47     private final int level;
  48     private final TypeKlass ownerClass;
  49 
  50     TryCatchBlockFactory(TypeKlass ownerClass, Type returnType,
  51             long complexityLimit, int statementLimit, int operatorLimit,
  52             int level, boolean subBlock, boolean canHaveBreaks,
  53             boolean canHaveContinues, boolean canHaveReturn) {
  54         this.ownerClass = ownerClass;
  55         this.returnType = returnType;
  56         this.complexityLimit = complexityLimit;
  57         this.statementLimit = statementLimit;
  58         this.operatorLimit = operatorLimit;
  59         this.level = level;
  60         this.subBlock = subBlock;
  61         this.canHaveBreaks = canHaveBreaks;
  62         this.canHaveContinues = canHaveContinues;
  63         this.canHaveReturn = canHaveReturn;
  64     }
  65 
  66     @Override
  67     public IRNode produce() throws ProductionFailedException {
  68         if (complexityLimit < 1 || statementLimit < 1) {
  69             throw new ProductionFailedException();
  70         }
  71         List<Type> uncheckedThrowables = getUncheckedThrowables();
  72         IRNodeBuilder builder = new IRNodeBuilder().setOwnerKlass(ownerClass)
  73                 .setResultType(returnType)
  74                 .setOperatorLimit(operatorLimit)
  75                 .setLevel(level)
  76                 .setSubBlock(subBlock)
  77                 .setCanHaveReturn(canHaveReturn)
  78                 .setCanHaveContinues(canHaveContinues)
  79                 .setCanHaveBreaks(canHaveBreaks);
  80         IRNode body = getBlock(builder, 0.6);
  81         int catchBlocksCount = (int) (CATCH_SELECTION_COEF
  82                 * PseudoRandom.random() * uncheckedThrowables.size());
  83         List<CatchBlock> catchBlocks = new ArrayList<>();
  84         List<Type> caught = new ArrayList<>();
  85         for (int i = 0; i < catchBlocksCount; i++) {
  86             List<Type> whatToCatch = new ArrayList<>();
  87             int throwableLimit = 1 + (int) ((1/(2*CATCH_SELECTION_COEF))
  88                     * PseudoRandom.random());
  89             for (int j = 0; j < throwableLimit; j++) {
  90                 whatToCatch.add(selectUniqueThrowable(uncheckedThrowables, caught));
  91             }
  92             catchBlocks.add(new CatchBlock(getBlock(builder, 0.3/catchBlocksCount),
  93                     whatToCatch, level));
  94         }
  95         IRNode finallyBody = PseudoRandom.randomBoolean() || catchBlocksCount == 0 ? getBlock(builder, 0.1) : null;
  96         return new TryCatchBlock(body, finallyBody, catchBlocks, level);
  97     }
  98 
  99     private Type selectUniqueThrowable(List<Type> variants, List<Type> caught) {
 100         Type selected;
 101         do {
 102             int randomIndex = PseudoRandom.randomNotZero(variants.size()) - 1;
 103             selected = variants.get(randomIndex);
 104         } while (caught.contains(selected));
 105         caught.add(selected);
 106         return selected;
 107     }
 108 
 109     private IRNode getBlock(IRNodeBuilder builder, double weight)
 110             throws ProductionFailedException {
 111         long actualComplexityLim = (long) (weight * PseudoRandom.random()
 112                 * complexityLimit);
 113         int actualStatementLim = (int) (weight * PseudoRandom.random()
 114                 * statementLimit);
 115         return builder.setStatementLimit(actualStatementLim)
 116                 .setComplexityLimit(actualComplexityLim)
 117                 .getBlockFactory()
 118                 .produce();
 119     }
 120 
 121     private List<Type> getUncheckedThrowables() {
 122         List<Type> result = new ArrayList<>();
 123         result.addAll(TypeUtil.getImplicitlyCastable(TypeList.getAll(),
 124                 new TypeKlass("java.lang.Error")));
 125         result.addAll(TypeUtil.getImplicitlyCastable(TypeList.getAll(),
 126                 new TypeKlass("java.lang.RuntimeException")));
 127         return result;
 128     }
 129 }