1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package compiler.compilercontrol.share.method;
  25 
  26 import compiler.compilercontrol.share.method.MethodDescriptor.PatternType;
  27 import compiler.compilercontrol.share.method.MethodDescriptor.Separator;
  28 import jdk.test.lib.Pair;
  29 import jdk.test.lib.Triple;
  30 import jdk.test.lib.Utils;
  31 import pool.PoolHelper;
  32 
  33 import java.lang.reflect.Executable;
  34 import java.util.ArrayList;
  35 import java.util.EnumSet;
  36 import java.util.List;
  37 import java.util.concurrent.Callable;
  38 import java.util.function.Function;
  39 
  40 /**
  41  * Generates combinations of method descriptors from the pool of methods
  42  */
  43 public class MethodGenerator {
  44     private static final List<Pair<Executable, Callable<?>>> METHODS =
  45             new PoolHelper().getAllMethods(PoolHelper.METHOD_FILTER);
  46     // Different combinations of patterns
  47     private static final List<Combination<PatternType>> PATTERNS_LIST;
  48     // Different combinations of separators
  49     private static final List<Combination<Separator>> SEPARATORS_LIST;
  50     // List of functions that modify elements
  51     private static final List<Function<String, String>> ELEMENT_MUTATORS;
  52 
  53     static {
  54         PATTERNS_LIST =
  55                 generate(EnumSet.allOf(PatternType.class),
  56                         EnumSet.allOf(PatternType.class),
  57                         EnumSet.of(PatternType.ANY, PatternType.EXACT));
  58         SEPARATORS_LIST =
  59                 generate(EnumSet.of(Separator.SLASH, Separator.DOT),
  60                         EnumSet.complementOf(EnumSet.of(Separator.NONE)),
  61                         EnumSet.of(Separator.COMMA, Separator.SPACE,
  62                                 Separator.NONE));
  63         ELEMENT_MUTATORS = generateMutators();
  64     }
  65 
  66     // Test method
  67     public static void main(String[] args) {
  68         MethodGenerator methodGenerator = new MethodGenerator();
  69         List<MethodDescriptor> tests = methodGenerator.getTests();
  70         tests.forEach(System.out::println);
  71     }
  72 
  73     /**
  74      * Generates random method descriptor
  75      *
  76      * @param executable executable used to generate descriptor
  77      * @return MethodDescriptor instance
  78      */
  79     public MethodDescriptor generateRandomDescriptor(Executable executable) {
  80         Combination<PatternType> patterns =
  81                 Utils.getRandomElement(PATTERNS_LIST);
  82         Combination<Separator> separators =
  83                 Utils.getRandomElement(SEPARATORS_LIST);
  84         // Create simple mutators for signature generation
  85         List<Function<String, String>> signMutators = new ArrayList<>();
  86         signMutators.add(input -> input);
  87         signMutators.add(input -> "");
  88         Combination<Function<String, String>> mutators = new Combination<>(
  89                 Utils.getRandomElement(ELEMENT_MUTATORS),
  90                 Utils.getRandomElement(ELEMENT_MUTATORS),
  91                 // use only this type of mutators
  92                 Utils.getRandomElement(signMutators));
  93         return makeMethodDescriptor(executable, patterns,
  94                 separators, mutators);
  95     }
  96 
  97     /**
  98      * Compile command signature that looks like java/lang/String.indexOf
  99      * http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html#BABDDFII
 100      *
 101      * @param executable executable used to generate descriptor
 102      * @return MethodDescriptor instance
 103      */
 104     public static MethodDescriptor commandDescriptor(Executable executable) {
 105         MethodDescriptor md = new MethodDescriptor(executable);
 106         md.aClass.setSeparator(Separator.SLASH);
 107         md.aMethod.setSeparator(Separator.DOT);
 108         md.aSignature.setSeparator(Separator.NONE);
 109         return md;
 110     }
 111 
 112     /**
 113      * Compile command signature that looks like java.lang.String::indexOf
 114      *
 115      * @param executable executable used to generate descriptor
 116      * @return MethodDescriptor instance
 117      */
 118     public static MethodDescriptor logDescriptor(Executable executable) {
 119         MethodDescriptor md = new MethodDescriptor(executable);
 120         md.aClass.setSeparator(Separator.DOT);
 121         md.aMethod.setSeparator(Separator.DOUBLECOLON);
 122         md.aSignature.setSeparator(Separator.NONE);
 123         return md;
 124     }
 125 
 126     /**
 127      * Method descriptor that matches any method. Its full signature is *.*
 128      *
 129      * @param executable executable used to generate descriptor
 130      * @return MethodDescriptor instance
 131      */
 132     public static MethodDescriptor anyMatchDescriptor(Executable executable) {
 133         MethodDescriptor md = new MethodDescriptor(executable);
 134         Combination<PatternType> patterns = new Combination<>(PatternType.ANY,
 135                 PatternType.ANY, PatternType.ANY);
 136         md.aClass.setSeparator(Separator.SLASH);
 137         md.aMethod.setSeparator(Separator.DOT);
 138         md.aSignature.setSeparator(Separator.NONE);
 139         md.setPatterns(patterns);
 140         return md;
 141     }
 142 
 143     /**
 144      * Generates a list of method patterns from the pool of methods
 145      *
 146      * @return a list of test cases
 147      */
 148     public List<MethodDescriptor> getTests() {
 149         List<MethodDescriptor> list = new ArrayList<>();
 150         METHODS.forEach(pair -> list.addAll(getTests(pair.first)));
 151         return list;
 152     }
 153 
 154     /**
 155      * Generates all combinations of method descriptors for a given executable
 156      *
 157      * @param executable executable for which the different combination is built
 158      * @return list of method descriptors
 159      */
 160     public List<MethodDescriptor> getTests(Executable executable) {
 161         List<MethodDescriptor> list = new ArrayList<>();
 162         for (Combination<PatternType> patterns : PATTERNS_LIST) {
 163             for (Combination<Separator> separators : SEPARATORS_LIST) {
 164                 for (Function<String, String> classGen : ELEMENT_MUTATORS) {
 165                     for (Function<String, String> methodGen :
 166                             ELEMENT_MUTATORS) {
 167                         for (Function<String, String> signatureGen :
 168                                 ELEMENT_MUTATORS) {
 169                             list.add(makeMethodDescriptor(executable,
 170                                     patterns, separators,
 171                                     new Combination<>(classGen, methodGen,
 172                                         signatureGen)));
 173                         }
 174                     }
 175                 }
 176             }
 177         }
 178         return list;
 179     }
 180 
 181     /**
 182      * Creates method descriptor from the given executable,
 183      * patterns and separators for its elements
 184      */
 185     private MethodDescriptor makeMethodDescriptor(
 186             Executable executable,
 187             Combination<PatternType> patterns,
 188             Combination<Separator> separators,
 189             Combination<Function<String, String>> mutators) {
 190         MethodDescriptor methodDescriptor = new MethodDescriptor(executable);
 191         methodDescriptor.setSeparators(separators);
 192         methodDescriptor.applyMutates(mutators);
 193         methodDescriptor.setPatterns(patterns);
 194         return methodDescriptor;
 195     }
 196 
 197     /**
 198      * Creates a list of functions that change given string
 199      */
 200     private static List<Function<String, String>> generateMutators() {
 201         List<Function<String, String>> elements = new ArrayList<>();
 202         // Use the input itself
 203         elements.add(input -> input);
 204         // Use half of the input string
 205         elements.add(input -> input.substring(input.length() / 2));
 206         // Add nonexistent element
 207         elements.add(input -> "nonexistent");
 208         // Use left and right angle brackets
 209         elements.add(input -> "<" + input + ">");
 210         // Embed * inside
 211         elements.add(input -> embed(input, "*"));
 212         // ** as a whole element
 213         elements.add(input -> "**");
 214         // Embed JLS-invalid letters
 215         elements.add(input -> embed(input, "@%"));
 216         elements.add(input -> embed(input, "]"));
 217         // Use JLS-invalid letters
 218         elements.add(input -> "-");
 219         elements.add(input -> "+");
 220         elements.add(input -> ")" + input);
 221         elements.add(input -> "{" + input + "}");
 222         // Add valid Java identifier start char
 223         elements.add(input -> "_" + input);
 224         elements.add(input -> "$" + input);
 225         elements.add(input -> "0" + input);
 226 
 227         /* TODO: uncomment this together with the fix for 8140631
 228         // Unicode characters
 229         elements.add(input -> embed(input, "\u0001"));
 230         elements.add(input -> embed(input, "\u007F"));
 231         // Combining character
 232         elements.add(input -> embed(input, "\u0300"));
 233         elements.add(input -> embed(input, "\u0306"));
 234         // Supplementary character
 235         elements.add(input -> new String(Character.toChars(0x1F64C)));
 236         */
 237         return elements;
 238     }
 239 
 240     /**
 241      * Embeds one string inside another one
 242      *
 243      * @param target  target source string
 244      * @param element string to be embedded into target string
 245      * @return result string
 246      */
 247     private static String embed(String target, String element) {
 248         int mid = target.length() / 2;
 249         String begin = target.substring(0, mid);
 250         String end = target.substring(mid);
 251         return begin + element + end;
 252     }
 253 
 254     /**
 255      * Generates triples from the given enum sets
 256      * for each of the method elements
 257      *
 258      * @param classSet  set of allowed elements for class
 259      * @param methodSet set of allowed elements for method
 260      * @param signSet   set of allowed elements for signature
 261      * @param <E>       type of generated triples
 262      * @return list of triples
 263      */
 264     private static <E extends Enum<E>> List<Combination<E>> generate(
 265             EnumSet<E> classSet, EnumSet<E> methodSet, EnumSet<E> signSet) {
 266         List<Combination<E>> list = new ArrayList<>();
 267         classSet.forEach(clsElement ->
 268             methodSet.forEach(methodElement ->
 269                 signSet.forEach(signElement ->
 270                     list.add(new Combination<>(clsElement, methodElement,
 271                             signElement))
 272                 )
 273             )
 274         );
 275         return list;
 276     }
 277 
 278     private static class Combination<T> extends Triple<T, T, T> {
 279         public Combination(T first, T second, T third) {
 280             super(first, second, third);
 281         }
 282     }
 283 }