/* * Copyright (c) 2013, 2018, 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 metaspace.stressHierarchy.common.generateHierarchy; import java.util.*; import vm.share.InMemoryJavaCompiler; public class GenerateHierarchyHelper { public static enum Type { CLASSES, INTERFACES, MIXED; } // Class-container that represents generated source file private static class ClassDescriptor {public String fullName; public CharSequence sourceCode; } private static enum Inheritance { CLASS_EXTENDS_CLASS, CLASS_IMPLEMENTS_INTERFACE, INTERFACE_EXTENDS_INTERFACE } private static final int EDGE_IN_MIXED_CASE = 30; private static Random random = new Random(); public static TreeDescriptor generateHierarchy(int depth, int minLevelSize, int maxLevelSize, Type type) { TreeDescriptor tree = new TreeDescriptor(); Map sourceMap = new HashMap(); int numberOfNodesInPrevLevel = 1; // generate root String packageName = composePackageName(0, 0); String className = packageName + ".Dummy"; switch (type) { case CLASSES: sourceMap.put(className, "package " + packageName +";\n public class Dummy { " + "public int calculate2() {return hashCode();} " + "public double calculate() {return hashCode() + 0.1;} " + "public String composeString() {return \"_root_\";}" + "}"); break; default: sourceMap.put(className, "package " + packageName + ";\n public interface Dummy {}"); } tree.addNode(0, 0, 0, className); for (int level = 1; level < depth; level++) { int nodesInLevel = minLevelSize + random.nextInt(maxLevelSize - minLevelSize); for (int nodeIndex = 0; nodeIndex < nodesInLevel; nodeIndex++) { int parent = random.nextInt(numberOfNodesInPrevLevel); Inheritance inheritance = null; switch (type) { case CLASSES: inheritance = Inheritance.CLASS_EXTENDS_CLASS; break; case INTERFACES: inheritance = Inheritance.INTERFACE_EXTENDS_INTERFACE; break; case MIXED: inheritance = level < EDGE_IN_MIXED_CASE ? Inheritance.INTERFACE_EXTENDS_INTERFACE : (level == EDGE_IN_MIXED_CASE ? Inheritance.CLASS_IMPLEMENTS_INTERFACE : Inheritance.CLASS_EXTENDS_CLASS); break; } ClassDescriptor classDescriptor = generateClassCode(level, nodeIndex, parent, inheritance); sourceMap.put(classDescriptor.fullName, classDescriptor.sourceCode); tree.addNode(level, nodeIndex, parent, classDescriptor.fullName); } numberOfNodesInPrevLevel = nodesInLevel; } Map bytecodeMap = InMemoryJavaCompiler.compile(sourceMap); for (NodeDescriptor nodeDescriptor : tree.nodeDescriptorList) { nodeDescriptor.bytecode = bytecodeMap.get(nodeDescriptor.className); } return tree; } private static String composePackageName(int level, int nodeIndex) { return "package_level" + level + "_num" + nodeIndex; } private static ClassDescriptor generateClassCode(int level, int nodeIndex, int parent, Inheritance inheritance) { ClassDescriptor result = new ClassDescriptor(); String packageName = composePackageName(level, nodeIndex); String parentPackage = composePackageName(level - 1, parent); result.fullName = packageName + ".Dummy"; StringBuffer source = new StringBuffer("package "); source.append(packageName + ";\n\n"); switch (inheritance) { case INTERFACE_EXTENDS_INTERFACE: source.append(" public interface Dummy extends " + parentPackage + ".Dummy {}"); break; case CLASS_EXTENDS_CLASS: source.append(" public class Dummy extends " + parentPackage + ".Dummy { " + "public int calculate2() {return (super.calculate2() + hashCode() % 1000);} " + "public double calculate() {return (super.calculate() + hashCode() + 0.1);} " + "public String composeString() {return super.composeString() + \"_" + packageName + "_\";}" + "}"); break; case CLASS_IMPLEMENTS_INTERFACE: source.append(" public class Dummy implements " + parentPackage + ".Dummy { " + "public int calculate2() {return hashCode();} " + "public double calculate() {return hashCode() + 0.1;} " + "public String composeString() {return \"_ancestor_class_\";}" + "}"); break; } result.sourceCode = source; return result; } }