| /* |
| * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package jdk.test.lib.jittester.factories; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| import jdk.test.lib.jittester.IRNode; |
| import jdk.test.lib.jittester.ProductionFailedException; |
| import jdk.test.lib.jittester.Symbol; |
| import jdk.test.lib.jittester.SymbolTable; |
| import jdk.test.lib.jittester.Type; |
| import jdk.test.lib.jittester.VariableInfo; |
| import jdk.test.lib.jittester.functions.Function; |
| import jdk.test.lib.jittester.functions.FunctionInfo; |
| import jdk.test.lib.jittester.types.TypeKlass; |
| import jdk.test.lib.jittester.utils.PseudoRandom; |
| |
| class FunctionFactory extends SafeFactory<Function> { |
| private final FunctionInfo functionInfo; |
| private final int operatorLimit; |
| private final long complexityLimit; |
| private final boolean exceptionSafe; |
| private final TypeKlass ownerClass; |
| |
| FunctionFactory(long complexityLimit, int operatorLimit, TypeKlass ownerClass, |
| Type resultType, boolean exceptionSafe) { |
| functionInfo = new FunctionInfo(); |
| this.complexityLimit = complexityLimit; |
| this.operatorLimit = operatorLimit; |
| this.ownerClass = ownerClass; |
| this.functionInfo.type = resultType; |
| this.exceptionSafe = exceptionSafe; |
| } |
| |
| @Override |
| protected Function sproduce() throws ProductionFailedException { |
| // Currently no function is exception-safe |
| if (exceptionSafe) { |
| throw new ProductionFailedException(); |
| } |
| ArrayList<Symbol> allFunctions; |
| if (functionInfo.type == null) { |
| allFunctions = new ArrayList<>(SymbolTable.getAllCombined(FunctionInfo.class)); |
| } else { |
| allFunctions = new ArrayList<>(SymbolTable.get(functionInfo.type, FunctionInfo.class)); |
| } |
| if (!allFunctions.isEmpty()) { |
| PseudoRandom.shuffle(allFunctions); |
| Collection<TypeKlass> klassHierarchy = ownerClass.getAllParents(); |
| for (Symbol function : allFunctions) { |
| FunctionInfo functionInfo = (FunctionInfo) function; |
| // Don't try to construct abstract classes. |
| if (functionInfo.isConstructor() && functionInfo.owner.isAbstract()) { |
| continue; |
| } |
| // We don't call methods from the same class which are not final, because if we |
| // do this may produce an infinite recursion. Simple example: |
| // class A |
| // { |
| // f1() { } |
| // f2() { f1(); } |
| // } |
| // |
| // class B : A |
| // { |
| // f1() { f2(); } |
| // } |
| // |
| // However the same example is obviously safe for static and final functions |
| // Also we introduce a special flag NONRECURSIVE to mark functions that |
| // are not overrided. We may also call such functions. |
| |
| // If it's a local call.. or it's a call using some variable to some object of some type in our hierarchy |
| boolean inHierarchy = false; |
| if (ownerClass.equals(functionInfo.owner) || (inHierarchy = klassHierarchy.contains(functionInfo.owner))) { |
| if ((functionInfo.flags & FunctionInfo.FINAL) == 0 && (functionInfo.flags & FunctionInfo.STATIC) == 0 |
| && (functionInfo.flags & FunctionInfo.NONRECURSIVE) == 0) { |
| continue; |
| } |
| if (inHierarchy && (functionInfo.flags & FunctionInfo.PRIVATE) > 0) { |
| continue; |
| } |
| } else { |
| if ((functionInfo.flags & FunctionInfo.PUBLIC) == 0 |
| && (functionInfo.flags & FunctionInfo.DEFAULT) == 0) { |
| continue; |
| } |
| } |
| if (functionInfo.complexity < complexityLimit - 1) { |
| try { |
| List<IRNode> accum = new ArrayList<>(); |
| if (!functionInfo.argTypes.isEmpty()) { |
| // Here we should do some analysis here to determine if |
| // there are any conflicting functions due to possible |
| // constant folding. |
| |
| // For example the following can be done: |
| // Scan all the hieirachy where the class is declared. |
| // If there are function with a same name and same number of args, |
| // then disable usage of foldable expressions in the args. |
| boolean noconsts = false; |
| Collection<Symbol> allFuncsInKlass = SymbolTable.getAllCombined(functionInfo.owner, |
| FunctionInfo.class); |
| for (Symbol s2 : allFuncsInKlass) { |
| FunctionInfo i2 = (FunctionInfo) function; |
| if (!i2.equals(functionInfo) && i2.name.equals(functionInfo.name) |
| && i2.argTypes.size() == functionInfo.argTypes.size()) { |
| noconsts = true; |
| break; |
| } |
| } |
| long argComp = (complexityLimit - 1 - functionInfo.complexity) / functionInfo.argTypes.size(); |
| int argumentOperatorLimit = (operatorLimit - 1) / functionInfo.argTypes.size(); |
| IRNodeBuilder b = new IRNodeBuilder().setOwnerKlass(ownerClass) |
| .setComplexityLimit(argComp) |
| .setOperatorLimit(argumentOperatorLimit) |
| .setExceptionSafe(exceptionSafe) |
| .setNoConsts(noconsts); |
| for (VariableInfo argType : functionInfo.argTypes) { |
| accum.add(b.setResultType(argType.type) |
| .getExpressionFactory() |
| .produce()); |
| } |
| } |
| return new Function(ownerClass, functionInfo, accum); |
| } catch (ProductionFailedException e) { |
| // removeAllChildren(); |
| } |
| } |
| } |
| } |
| throw new ProductionFailedException(); |
| } |
| } |