# HG changeset patch # User kzhaldyb # Date 1461250870 -10800 # Node ID 8dd94eb5dcfc638ed212cb15717b5a5781bfe3b1 # Parent 8731fa11f766491561e78f6133e357c8315412cd 8153764: Add auxiliary method that generates class by class prototype to gc testlibrary Reviewed-by: dfazunen, iignatyev diff -r 8731fa11f766 -r 8dd94eb5dcfc hotspot/test/gc/testlibrary/Helpers.java --- 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: + *
+ * 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; + *
+ * } + * + * @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) {