001/* 002 * Copyright (c) 2015, 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.truffle.test; 024 025import static com.oracle.graal.graph.test.matchers.NodeIterableCount.*; 026import static com.oracle.graal.graph.test.matchers.NodeIterableIsEmpty.*; 027import static org.hamcrest.core.IsInstanceOf.*; 028import static org.junit.Assert.*; 029import jdk.internal.jvmci.meta.*; 030 031import org.junit.*; 032 033import sun.misc.*; 034 035import com.oracle.graal.compiler.test.*; 036import com.oracle.graal.graph.iterators.*; 037import com.oracle.graal.graphbuilderconf.*; 038import com.oracle.graal.nodes.*; 039import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; 040import com.oracle.graal.nodes.extended.*; 041import com.oracle.graal.nodes.memory.*; 042import com.oracle.graal.nodes.spi.LoweringTool.StandardLoweringStage; 043import com.oracle.graal.phases.common.*; 044import com.oracle.graal.phases.tiers.*; 045import com.oracle.graal.truffle.nodes.*; 046import com.oracle.graal.truffle.substitutions.*; 047import com.oracle.truffle.api.*; 048import com.oracle.truffle.api.unsafe.*; 049 050public class ConditionAnchoringTest extends GraalCompilerTest { 051 private static final UnsafeAccess access; 052 private static final long offset; 053 private static final Object location = new Object(); 054 055 static { 056 Unsafe unsafe = jdk.internal.jvmci.common.UnsafeAccess.unsafe; 057 access = Truffle.getRuntime().getCapability(UnsafeAccessFactory.class).createUnsafeAccess(unsafe); 058 long fieldOffset = 0; 059 try { 060 fieldOffset = unsafe.objectFieldOffset(CheckedObject.class.getDeclaredField("field")); 061 } catch (NoSuchFieldException | SecurityException e) { 062 e.printStackTrace(); 063 } 064 offset = fieldOffset; 065 } 066 067 private static class CheckedObject { 068 int id; 069 int iid; 070 @SuppressWarnings("unused") int field; 071 } 072 073 public int checkedAccess(CheckedObject o) { 074 if (o.id == 42) { 075 return access.getInt(o, offset, o.id == 42, location); 076 } 077 return -1; 078 } 079 080 // test with a different kind of condition (not a comparison against a constant) 081 public int checkedAccess2(CheckedObject o) { 082 if (o.id == o.iid) { 083 return access.getInt(o, offset, o.id == o.iid, location); 084 } 085 return -1; 086 } 087 088 @Test 089 public void test() { 090 test("checkedAccess", 1); 091 } 092 093 @Test 094 public void test2() { 095 test("checkedAccess2", 2); 096 } 097 098 public void test(String name, int ids) { 099 StructuredGraph graph = parseEager(name, AllowAssumptions.YES); 100 101 NodeIterable<UnsafeLoadNode> unsafeNodes = graph.getNodes().filter(UnsafeLoadNode.class); 102 assertThat(unsafeNodes, hasCount(1)); 103 104 // lower unsafe load 105 PhaseContext context = new PhaseContext(getProviders()); 106 LoweringPhase lowering = new LoweringPhase(new CanonicalizerPhase(), StandardLoweringStage.HIGH_TIER); 107 lowering.apply(graph, context); 108 109 unsafeNodes = graph.getNodes().filter(UnsafeLoadNode.class); 110 NodeIterable<ConditionAnchorNode> conditionAnchors = graph.getNodes().filter(ConditionAnchorNode.class); 111 NodeIterable<ReadNode> reads = graph.getNodes().filter(ReadNode.class); 112 assertThat(unsafeNodes, isEmpty()); 113 assertThat(conditionAnchors, hasCount(1)); 114 assertThat(reads, hasCount(2 * ids + 1)); // 2 * ids id reads, 1 'field' access 115 116 // float reads and canonicalize to give a chance to conditions to GVN 117 FloatingReadPhase floatingReadPhase = new FloatingReadPhase(); 118 floatingReadPhase.apply(graph); 119 CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(); 120 canonicalizerPhase.apply(graph, context); 121 122 NodeIterable<FloatingReadNode> floatingReads = graph.getNodes().filter(FloatingReadNode.class); 123 assertThat(floatingReads, hasCount(ids + 1)); // 1 id read, 1 'field' access 124 125 // apply DominatorConditionalEliminationPhase 126 DominatorConditionalEliminationPhase conditionalElimination = new DominatorConditionalEliminationPhase(false); 127 conditionalElimination.apply(graph); 128 129 floatingReads = graph.getNodes().filter(FloatingReadNode.class).filter(n -> ((FloatingReadNode) n).getLocationIdentity() instanceof ObjectLocationIdentity); 130 conditionAnchors = graph.getNodes().filter(ConditionAnchorNode.class); 131 assertThat(floatingReads, hasCount(1)); 132 assertThat(conditionAnchors, isEmpty()); 133 FloatingReadNode readNode = floatingReads.first(); 134 assertThat(readNode.getGuard(), instanceOf(BeginNode.class)); 135 assertThat(readNode.getGuard().asNode().predecessor(), instanceOf(IfNode.class)); 136 } 137 138 @Override 139 protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) { 140 // get UnsafeAccessImpl.unsafeGetInt intrinsified 141 TruffleGraphBuilderPlugins.registerUnsafeAccessImplPlugins(conf.getPlugins().getInvocationPlugins(), false); 142 // get UnsafeAccess.getInt inlined 143 conf.getPlugins().appendInlineInvokePlugin(new InlineEverythingPlugin()); 144 return super.editGraphBuilderConfiguration(conf); 145 } 146 147 private static final class InlineEverythingPlugin implements InlineInvokePlugin { 148 @Override 149 public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) { 150 assert method.hasBytecodes(); 151 return new InlineInfo(method, false); 152 } 153 } 154}