blob: 7815ca6dd9f1a3f8cf587c4e3aacfb8cff72323f [file] [log] [blame]
/*
* 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<String, CharSequence> sourceMap = new HashMap<String, CharSequence>();
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<String, byte[]> 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;
}
}