/*
 * Copyright (c) 2015, 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.
 */

/**
 * @test
 * @bug 8139771
 * @summary Eliminating CastPP nodes at Phis when they all come from a unique input may cause crash
 * @requires vm.gc=="Serial" | vm.gc=="Parallel"
 *
 * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement
 *      -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:+StressGCM
 *      compiler.controldependency.TestEliminatedCastPPAtPhi
 *
 */

package compiler.controldependency;

public class TestEliminatedCastPPAtPhi {

    static TestEliminatedCastPPAtPhi saved;
    static TestEliminatedCastPPAtPhi saved_not_null;

    int f;

    static int test(TestEliminatedCastPPAtPhi obj, int[] array, boolean flag) {
        int ret = array[0] + array[20];
        saved = obj;
        if (obj == null) {
            return ret;
        }
        saved_not_null = obj;

        // empty loop to be optimized out. Delays range check smearing
        // for the array access below until the if diamond is
        // optimized out
        int i = 0;
        for (; i < 10; i++);

        ret += array[i];

        TestEliminatedCastPPAtPhi res;
        if (flag) {
            // load is optimized out and res is obj here
            res = saved;
        } else {
            // load is optimized out and res is non null CastPP of res here
            res = saved_not_null;
        }
        // null check + CastPP here for res field load below

        // 1) null check is pushed in the branches of the if above by
        // split through phi because res is non null in the second
        // branch and the null check can be optimized out in that
        // branch. The Castpp stays here.

        // 2) null check in the first branch is also optimized out
        // because a dominating null check is found (the explicit null
        // check at the beggining of the test)

        // 3) the Phi for the if above merges a CastPP'ed value and
        // the same value so it's optimized out and replaced by the
        // uncasted value: obj

        // 4) the if above has 2 empty branches so it's optimized
        // out. The control of the CastPP that is still here is now
        // the success branch of the range check for the array access
        // above

        // 5) the loop above is optimized out, i = 10, the range check
        // for the array access above is optimized out and all its
        // uses are replaced by the range check for the array accesses
        // at the beginning of the method. The castPP here is one of
        // the uses and so its control is now the range check at the
        // beginning of the method: the control of the CastPP bypasses
        // the explicit null check

        return ret + res.f;
    }

    static public void main(String[] args) {
        int[] array = new int[100];
        TestEliminatedCastPPAtPhi obj = new TestEliminatedCastPPAtPhi();
        for (int i = 0; i < 20000; i++) {
            test(obj, array, (i%2) == 0);
        }
        test(null, array, true);
    }

}
