--- a/hotspot/test/gc/testlibrary/Helpers.java Thu Apr 21 09:23:04 2016 -0400
+++ b/hotspot/test/gc/testlibrary/Helpers.java Thu Apr 21 18:01:10 2016 +0300
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016 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
@@ -32,6 +32,7 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
public class Helpers {
@@ -45,14 +46,14 @@
/**
* According class file format theoretical amount of fields in class is u2 which is (256 * 256 - 1).
- * Some service info takes place in constant pool and we really could make a class with only (256 * 256 - 29)
- * fields.
+ * Some service info takes place in constant pool and we really could make a class with lesser amount of fields.
+ *
* Since the exact value is not so important and I would like to avoid issues that may be caused by future changes/
- * different archs etc I selected (256 * 256 - 32) for this constant.
+ * different archs etc I selected (256 * 256 - 1024) for this constant.
* The test works with other values too but the smaller the number the more classes we need to generate and it takes
* more time
*/
- private static final int MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS = 256 * 256 - 32;
+ private static final int MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS = 256 * 256 - 1024;
/**
* Detects amount of extra bytes required to allocate a byte array.
@@ -140,6 +141,28 @@
}
/**
+ * Generates specified amount of long fields
+ * Result string will looks like this:
+ * <p>
+ * long f0;
+ * ...
+ * long fNNN;
+ *
+ * @param fieldCount count of long fields
+ * @return generated fields
+ */
+ private static String fieldsGenerator(long fieldCount) {
+ StringBuilder fieldsBuilder = new StringBuilder();
+
+ for (int i = 0; i < fieldCount; ++i) {
+ fieldsBuilder.append(String.format("long f%d;\n", i));
+ }
+
+ return fieldsBuilder.toString();
+ }
+
+
+ /**
* Changes string from enum notation to class notation - i.e. "VERY_SMALL_CAT" to "VerySmallCat"
*
* @param enumName string in enum notation
@@ -216,22 +239,121 @@
// for the last generated class we use specified class name
String clsName = (i == generatedClassesCount - 1) ? className : prefix + i;
- Helpers.compileClass(clsName, workDir,
- Helpers.generate(
- clsName,
- // for first generated class we don't have 'extends'
- (i == 0 ? null : prefix + (i - 1)),
- null,
- // for the last generated class we use different field count
- (i == generatedClassesCount - 1) ? fieldsInLastClassCount
- : MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS));
+ // If we already have a file with the same name we do not create it again
+ if (Files.notExists(Paths.get(clsName + ".java"))) {
+ Helpers.compileClass(clsName, workDir,
+ Helpers.generate(
+ clsName,
+ // for first generated class we don't have 'extends'
+ (i == 0 ? null : prefix + (i - 1)),
+ null,
+ // for the last generated class we use different field count
+ (i == generatedClassesCount - 1) ? fieldsInLastClassCount
+ : MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS));
+ } else {
+ System.out.println("Class " + clsName +
+ ".java already exists, skipping class' generation and compilation");
+ }
+
}
return classLoader.loadClass(className);
}
/**
+ * Creates a class which instances will be approximately of the requested size.
+ * This method produces a java source from a class template by substituting values instead of parameters.
+ * Then the obtained source is compiled.
+ * Generated class will looks like this:
+ * classTemplate
+ * constructorTemplate
+ * long f0;
+ * ...
+ * long fNNN;
+ * <p>
+ * }
+ *
+ * @param className generated class name
+ * @param baseClass base class
+ * @param classTemplate class template - the first part of class. ${ClassName} and ${BaseClass} will be replaced
+ * with values from className and baseClass,one entry of ${Fields} will be replaced with
+ * generated long fields. Class template should look like this:
+ * imports;
+ * public class ${ClassName} extends ${BaseClass} {
+ * public ${ClassName} { some code here;}
+ * some methods
+ * ${Fields}
+ *
+ * }
+ * @param constructorTemplate constructor template, ${ClassName} would be replaced on actual class name
+ * @param instanceSize size of generated class' instance. Size should be aligned by 8 bytes
+ * @param workDir working dir where generated classes are put and compiled
+ * @param prefix prefix for service classes (ones we use to create chain of inheritance).
+ * The names will be prefix_1, prefix_2,.., prefix_n
+ * @return Class object of generated and compiled class loaded in specified class loader
+ * @throws IOException if cannot write or read to workDir
+ */
+ public static void generateByTemplateAndCompile(String className, String baseClass, String classTemplate,
+ String constructorTemplate, long instanceSize, Path workDir,
+ String prefix) throws IOException {
+
+ if (instanceSize % SIZE_OF_LONG != 0L) {
+ throw new Error(String.format("Test bug: only sizes aligned by %d bytes are supported and %d was specified",
+ SIZE_OF_LONG, instanceSize));
+ }
+
+ int instanceSizeWithoutObjectHeaderInWords =
+ (int) (instanceSize - WhiteBox.getWhiteBox().getObjectSize(new Object())) / SIZE_OF_LONG;
+
+ if (instanceSizeWithoutObjectHeaderInWords <= 0) {
+ throw new Error(String.format("Test bug: specified instance size is too small - %d."
+ + " Cannot generate any classes", instanceSize));
+ }
+
+ int sizeOfLastFile = instanceSizeWithoutObjectHeaderInWords % MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS;
+ int generatedClassesCount = instanceSizeWithoutObjectHeaderInWords / MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS;
+
+ // Do all the classes have the maximum number of fields?
+ int fieldsInLastClassCount;
+
+ if (sizeOfLastFile == 0) {
+ fieldsInLastClassCount = MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS;
+ } else {
+ generatedClassesCount++;
+ fieldsInLastClassCount = sizeOfLastFile;
+ }
+
+ // first (generatedClassesCount - 1) classes are just fillers - just long fields and constructor
+ for (int i = 0; i < generatedClassesCount - 1; i++) {
+ String clsName = prefix + i;
+
+ Helpers.compileClass(clsName, workDir,
+ Helpers.generate(
+ clsName,
+ // first generated class extends base class
+ (i == 0 ? baseClass : prefix + (i - 1)),
+ constructorTemplate.replace("${ClassName}", clsName),
+ MAXIMUM_AMOUNT_OF_FIELDS_IN_CLASS));
+ }
+
+ // generating last class - the one with specified className
+ Helpers.compileClass(className, workDir,
+ classTemplate.replaceAll("\\$\\{ClassName\\}", className)
+ // if no fillers were generated (generatedClassesCount == 1)
+ // the last class should extends baseClass
+ // otherwise it should extend last generated filler class which name is
+ // prefix + (generatedClassesCount - 2)
+ // generatedClassesCount is always not smaller than 1
+ .replace("${BaseClass}",
+ generatedClassesCount == 1 ? baseClass :
+ prefix + (generatedClassesCount - 2))
+ .replace("${Fields}", fieldsGenerator(fieldsInLastClassCount))
+ );
+ }
+
+ /**
* Waits until Concurent Mark Cycle finishes
- * @param wb Whitebox instance
+ *
+ * @param wb Whitebox instance
* @param sleepTime sleep time
*/
public static void waitTillCMCFinished(WhiteBox wb, int sleepTime) {