/* * Copyright (c) 2011, 2014, 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 org.graalvm.compiler.core.test.ea; import java.util.List; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaMethod; import org.junit.Assert; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.debug.Debug; import org.graalvm.compiler.debug.Debug.Scope; import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.nodes.java.NewArrayNode; import org.graalvm.compiler.nodes.java.NewInstanceNode; import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; import org.graalvm.compiler.phases.common.inlining.InliningPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; //JaCoCo Exclude /** * This base class for all Escape Analysis tests does not contain tests itself, therefore it is not * automatically excluded from JaCoCo. Since it includes code that is used in the test snippets, it * needs to be excluded manually. */ public class EATestBase extends GraalCompilerTest { public static class TestClassInt { public int x; public int y; public int z; public TestClassInt() { this(0, 0); } public TestClassInt(int x) { this(x, 0); } public TestClassInt(int x, int y) { this.x = x; this.y = y; } @Override public boolean equals(Object obj) { TestClassInt other = (TestClassInt) obj; return x == other.x && y == other.y && z == other.z; } @Override public String toString() { return "{" + x + "," + y + "}"; } @Override public int hashCode() { return x + 13 * y; } } public static class TestClassObject { public Object x; public Object y; public TestClassObject() { this(null, null); } public TestClassObject(Object x) { this(x, null); } public TestClassObject(Object x, Object y) { this.x = x; this.y = y; } @Override public boolean equals(Object obj) { TestClassObject other = (TestClassObject) obj; return x == other.x && y == other.y; } @Override public String toString() { return "{" + x + "," + y + "}"; } @Override public int hashCode() { return (x == null ? 0 : x.hashCode()) + 13 * (y == null ? 0 : y.hashCode()); } } protected static native void notInlineable(); protected StructuredGraph graph; protected HighTierContext context; protected List returnNodes; /** * Runs Escape Analysis on the given snippet and makes sure that no allocations remain in the * graph. * * @param snippet the name of the method whose graph should be processed * @param expectedConstantResult if this is non-null, the resulting graph needs to have the * given constant return value * @param iterativeEscapeAnalysis true if escape analysis should be run for more than one * iteration */ protected void testEscapeAnalysis(String snippet, JavaConstant expectedConstantResult, boolean iterativeEscapeAnalysis) { prepareGraph(snippet, iterativeEscapeAnalysis); if (expectedConstantResult != null) { for (ReturnNode returnNode : returnNodes) { Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant()); Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); } } int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() + graph.getNodes().filter(CommitAllocationNode.class).count(); Assert.assertEquals(0, newInstanceCount); } @SuppressWarnings("try") protected void prepareGraph(String snippet, boolean iterativeEscapeAnalysis) { ResolvedJavaMethod method = getResolvedJavaMethod(snippet); try (Scope s = Debug.scope(getClass(), method, getCodeCache())) { graph = parseEager(method, AllowAssumptions.YES); context = getDefaultHighTierContext(); new InliningPhase(new CanonicalizerPhase()).apply(graph, context); new DeadCodeEliminationPhase().apply(graph); new CanonicalizerPhase().apply(graph, context); new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(), null).apply(graph, context); returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot(); } catch (Throwable e) { throw Debug.handle(e); } } }