test/hotspot/jtreg/vmTestbase/jit/graph/Globals.java
author iignatyev
Fri, 11 Oct 2019 09:43:41 -0700
changeset 58564 218a1a642c6f
parent 50366 4d85990f9c4a
permissions -rw-r--r--
8225654: rework vmTestbase/jit/graph Reviewed-by: thartmann, neliasso

/*
 * Copyright (c) 1998, 2019, 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 jit.graph;

import jdk.test.lib.Utils;
import nsk.share.TestFailure;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Vector;

public final class Globals {


    public static int STATIC_LOOP = 0;
    public static int NUM_TEST_CLASSES = 7;
    public static long RANDOM_LOOP = 100;
    public static boolean VERBOSE = false;

    private static final Random indexGenerator = Utils.getRandomInstance();
    private static String[] ClassArray = null;
    private static Class[] ClassInstanceArray = null;
    private static int maxClassIndex = 0;

    private static String[] MethodName_Array = null;
    private static Method[] MethodInstance_Array = null;

    // Should be prime, so that odds of an incorrect verification reduced
    public static int[] MethodID_Array = null;

    public static synchronized void initialize(String testListPath) {
        File td = new File(testListPath);
        if (!td.exists()) {
            throw new Error("TESTBUG: File " + testListPath + " Not found");
        }

        if (!td.isFile()) {
            throw new Error("TESTBUG: " + testListPath + " Must be a File");
        }

        BufferedReader classList = null;
        try {
            try {
                classList = new BufferedReader(new FileReader(td));
            } catch (FileNotFoundException e) {
                throw new Error("TESTBUG: Error finding Classlist", e);
            }

            String line = null;
            try {
                line = classList.readLine();
            } catch (IOException e) {
                throw new Error("TESTBUG: Error reading Classlist", e);
            }

            try {
                // ClassArray.length;
                maxClassIndex = Math.abs(Integer.parseInt(line));
            } catch (NumberFormatException e) {
                throw new Error("TESTBUG: Error reading Classlist - first number must be number of methods defined", e);
            }

            ClassArray = new String[maxClassIndex];
            ClassInstanceArray = new Class[maxClassIndex];
            MethodName_Array = new String[maxClassIndex];
            MethodInstance_Array = new Method[maxClassIndex];
            MethodID_Array = new int[maxClassIndex];

            int i;
            for (i = 0; i < maxClassIndex; i++) {
                try {
                    line = classList.readLine();
                } catch (IOException e) {
                    throw new Error("TESTBUG: Error reading ClasslistFile: testListPath", e);
                }
                StringTokenizer lineTokens = new StringTokenizer(line, "\t ");
                if (lineTokens.countTokens() < 3) {
                    throw new Error("TESTBUG: ClasslistFile: unexpected line:" + line);
                } else {
                    ClassArray[i] = lineTokens.nextToken();
                    MethodName_Array[i] = lineTokens.nextToken();
                    MethodID_Array[i] = Integer.parseInt(lineTokens.nextToken());
                }
            }
            maxClassIndex = i;
        } finally {
            if (classList != null) {
                try {
                    classList.close();
                } catch (IOException e) {
                    throw new Error("can't close file", e);
                }
            }
        }

        if ((NUM_TEST_CLASSES < ClassArray.length) && (NUM_TEST_CLASSES > 0)) {
            maxClassIndex = NUM_TEST_CLASSES;
        } else {
            NUM_TEST_CLASSES = maxClassIndex;
        }
    }

    // does a binary search to find the index for the ID of a method
    private static int ID_BinSearch(int begin, int end, int ID) {
        if (end < begin) {
            return (-1);
        }

        int mid = (begin + end) / 2;
        int midvalue = MethodID_Array[mid];

        if (ID == midvalue) {
            return (mid);
        } else if (ID < midvalue) {
            return (ID_BinSearch(begin, mid - 1, ID));
        } else {
            return (ID_BinSearch(mid + 1, end, ID));
        }
    }


    // based off a static index, this function selects the method to be called
    public static MethodData returnNextStaticMethod(int Method_ID) {
        //int i = ID_BinSearch(0, MethodID_Array.length - 1, Method_ID);
        int i = ID_BinSearch(0, maxClassIndex - 1, Method_ID);

        return (nextStaticMethod((i == -1) ? 0 : i));
    }

    // this function randomly selects the next method to be called by the test class
    public static MethodData nextRandomMethod() {
        int i = indexGenerator.nextInt(maxClassIndex);
        return (nextStaticMethod(i));
    }

    private static MethodData nextStaticMethod(int i) {
        Class methodsClass = null;
        Method nextMethod = null;

        try {
            methodsClass = ClassInstanceArray[i];
            if (methodsClass == null) {
                methodsClass = Class.forName(ClassArray[i]);
                ClassInstanceArray[i] = methodsClass;
            }
            nextMethod = MethodInstance_Array[i];
            if (nextMethod == null) {
                nextMethod = methodsClass.getMethod(MethodName_Array[i],
                        Vector.class, Vector.class,  Long.class, Integer.class);
                // sum vector, ID vector, function depth, static function call depth
                MethodInstance_Array[i] = nextMethod;
            }
        } catch (ClassNotFoundException e) {
            throw new Error("TESTBUG Class: " + ClassArray[i] + " Not Found", e);
        } catch (NoSuchMethodException e) {
            throw new Error("TESTBUG Method: " + ClassArray[i] + "::" + MethodName_Array[i] + " Not Found", e);
        } catch (SecurityException e) {
            throw new Error("TESTBUG Security Exception Generated by " + ClassArray[i] + "::" + MethodName_Array[i], e);
        }
        return new MethodData(ClassArray[i], MethodName_Array[i], methodsClass, nextMethod, MethodID_Array[i]);
    }


    /* These two functions are used to verify that all function were called in the proper order */

    // called by "parent" function to add childs ID to vector
    public static void addFunctionIDToVector(int FunctionIndex, Vector IDVector) {
        IDVector.addElement(FunctionIndex);
    }

    // called by "child" to add Function Index to Vector
    public static void appendSumToSummationVector(int FunctionIndex, Vector SummationVector) {
        if (SummationVector.isEmpty()) {
            SummationVector.addElement((long) FunctionIndex);
        } else {
            SummationVector.addElement((Long) SummationVector.lastElement() + FunctionIndex);
        }
    }

    // This function calls a method based off of MethodData
    public static void callMethod(MethodData methodCallStr,
                                  Vector summation, Vector ID,
                                  Long numFcalls, Integer staticFcalls)
            throws InvocationTargetException {
        try {
            methodCallStr.nextMethod.invoke(methodCallStr.instance,
                    summation, ID, numFcalls, staticFcalls);
        } catch (IllegalAccessException e) {
            // should never happen with a valid testfile
            throw new TestFailure("Illegal Access Exception", e);
        }
    }
}