001/*
002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.compiler.test;
024
025import com.oracle.graal.debug.*;
026import com.oracle.graal.debug.Debug.*;
027
028import org.junit.*;
029
030import com.oracle.graal.nodes.*;
031import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
032import com.oracle.graal.nodes.memory.*;
033import com.oracle.graal.nodes.spi.*;
034import com.oracle.graal.phases.common.*;
035import com.oracle.graal.phases.tiers.*;
036
037/* consider
038 *     B b = (B) a;
039 *     return b.x10;
040 *
041 * With snippets a typecheck is performed and if it was successful, a UnsafeCastNode is created.
042 * For the read node, however, there is only a dependency to the UnsafeCastNode, but not to the
043 * typecheck itself. With special crafting, it's possible to get the scheduler moving the
044 * FloatingReadNode before the typecheck. Assuming the object is of the wrong type (here for
045 * example A), an invalid field read is done.
046 *
047 * In order to avoid this situation, an anchor node is introduced in CheckCastSnippts.
048 */
049
050public class ReadAfterCheckCastTest extends GraphScheduleTest {
051
052    public static long foo = 0;
053
054    public static class A {
055
056        public long x1;
057    }
058
059    public static class B extends A {
060
061        public long x10;
062    }
063
064    public static long test1Snippet(A a) {
065        if (foo > 4) {
066            B b = (B) a;
067            b.x10 += 1;
068            return b.x10;
069        } else {
070            B b = (B) a;
071            b.x10 += 1;
072            return b.x10;
073        }
074    }
075
076    @Test
077    public void test1() {
078        test("test1Snippet");
079    }
080
081    private void test(final String snippet) {
082        try (Scope s = Debug.scope("ReadAfterCheckCastTest", new DebugDumpScope(snippet))) {
083            // check shape of graph, with lots of assumptions. will probably fail if graph
084            // structure changes significantly
085            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
086            PhaseContext context = new PhaseContext(getProviders());
087            CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
088            new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
089            new FloatingReadPhase().apply(graph);
090            new OptimizeGuardAnchorsPhase().apply(graph);
091            canonicalizer.apply(graph, context);
092
093            Debug.dump(graph, "After lowering");
094
095            for (FloatingReadNode node : graph.getNodes(ParameterNode.TYPE).first().usages().filter(FloatingReadNode.class)) {
096                // Checking that the parameter a is not directly used for the access to field
097                // x10 (because x10 must be guarded by the checkcast).
098                Assert.assertTrue(node.getLocationIdentity().isImmutable());
099            }
100        } catch (Throwable e) {
101            throw Debug.handle(e);
102        }
103    }
104}