001/*
002 * Copyright (c) 2011, 2014, 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.ea;
024
025import java.util.*;
026
027import com.oracle.graal.debug.*;
028import com.oracle.graal.debug.Debug.*;
029import jdk.internal.jvmci.meta.*;
030
031import org.junit.*;
032
033import com.oracle.graal.compiler.test.*;
034import com.oracle.graal.nodes.*;
035import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
036import com.oracle.graal.nodes.java.*;
037import com.oracle.graal.nodes.virtual.*;
038import com.oracle.graal.phases.common.*;
039import com.oracle.graal.phases.common.inlining.*;
040import com.oracle.graal.phases.tiers.*;
041import com.oracle.graal.virtual.phases.ea.*;
042
043//JaCoCo Exclude
044
045/**
046 * This base class for all Escape Analysis tests does not contain tests itself, therefore it is not
047 * automatically excluded from JaCoCo. Since it includes code that is used in the test snippets, it
048 * needs to be excluded manually.
049 */
050public class EATestBase extends GraalCompilerTest {
051
052    public static class TestClassInt {
053        public int x;
054        public int y;
055        public int z;
056
057        public TestClassInt() {
058            this(0, 0);
059        }
060
061        public TestClassInt(int x) {
062            this(x, 0);
063        }
064
065        public TestClassInt(int x, int y) {
066            this.x = x;
067            this.y = y;
068        }
069
070        @Override
071        public boolean equals(Object obj) {
072            TestClassInt other = (TestClassInt) obj;
073            return x == other.x && y == other.y && z == other.z;
074        }
075
076        @Override
077        public String toString() {
078            return "{" + x + "," + y + "}";
079        }
080
081        @Override
082        public int hashCode() {
083            return x + 13 * y;
084        }
085    }
086
087    public static class TestClassObject {
088        public Object x;
089        public Object y;
090
091        public TestClassObject() {
092            this(null, null);
093        }
094
095        public TestClassObject(Object x) {
096            this(x, null);
097        }
098
099        public TestClassObject(Object x, Object y) {
100            this.x = x;
101            this.y = y;
102        }
103
104        @Override
105        public boolean equals(Object obj) {
106            TestClassObject other = (TestClassObject) obj;
107            return x == other.x && y == other.y;
108        }
109
110        @Override
111        public String toString() {
112            return "{" + x + "," + y + "}";
113        }
114
115        @Override
116        public int hashCode() {
117            return (x == null ? 0 : x.hashCode()) + 13 * (y == null ? 0 : y.hashCode());
118        }
119    }
120
121    protected static native void notInlineable();
122
123    protected StructuredGraph graph;
124    protected HighTierContext context;
125    protected List<ReturnNode> returnNodes;
126
127    /**
128     * Runs Escape Analysis on the given snippet and makes sure that no allocations remain in the
129     * graph.
130     *
131     * @param snippet the name of the method whose graph should be processed
132     * @param expectedConstantResult if this is non-null, the resulting graph needs to have the
133     *            given constant return value
134     * @param iterativeEscapeAnalysis true if escape analysis should be run for more than one
135     *            iteration
136     */
137    protected void testEscapeAnalysis(String snippet, JavaConstant expectedConstantResult, boolean iterativeEscapeAnalysis) {
138        prepareGraph(snippet, iterativeEscapeAnalysis);
139        if (expectedConstantResult != null) {
140            for (ReturnNode returnNode : returnNodes) {
141                Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant());
142                Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant());
143            }
144        }
145        int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() +
146                        graph.getNodes().filter(CommitAllocationNode.class).count();
147        Assert.assertEquals(0, newInstanceCount);
148    }
149
150    protected void prepareGraph(String snippet, boolean iterativeEscapeAnalysis) {
151        ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
152        try (Scope s = Debug.scope(getClass(), method, getCodeCache())) {
153            graph = parseEager(method, AllowAssumptions.YES);
154            context = getDefaultHighTierContext();
155            new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
156            new DeadCodeEliminationPhase().apply(graph);
157            new CanonicalizerPhase().apply(graph, context);
158            new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(), null).apply(graph, context);
159            returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot();
160        } catch (Throwable e) {
161            throw Debug.handle(e);
162        }
163    }
164}