1 /* 2 * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.core.test.ea; 26 27 import java.lang.reflect.Field; 28 29 import org.graalvm.compiler.core.common.GraalOptions; 30 import org.graalvm.compiler.core.test.GraalCompilerTest; 31 import org.graalvm.compiler.nodes.StructuredGraph; 32 import org.graalvm.compiler.nodes.extended.RawLoadNode; 33 import org.graalvm.compiler.nodes.extended.RawStoreNode; 34 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; 35 import org.graalvm.compiler.phases.common.CanonicalizerPhase; 36 import org.graalvm.compiler.phases.common.inlining.InliningPhase; 37 import org.graalvm.compiler.phases.tiers.HighTierContext; 38 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; 39 import org.junit.Test; 40 41 import sun.misc.Unsafe; 42 43 public class TrufflePEATest extends GraalCompilerTest { 44 45 /** 46 * This class mimics the behavior of {@code FrameWithoutBoxing}. 47 */ 48 static class Frame { 49 long[] primitiveLocals; 50 51 Frame(int size) { 52 primitiveLocals = new long[size]; 53 } 54 } 55 56 /** 57 * This class mimics the behavior of {@code DynamicObjectL6I6}. 58 */ 59 static class DynamicObject { 60 int primitiveField0; 61 int primitiveField1; 62 int primitiveField2; 63 } 64 65 private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1; 66 private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2; 67 68 private static final long primitiveField0Offset; 69 70 static { 71 try { 72 Field primitiveField0 = DynamicObject.class.getDeclaredField("primitiveField0"); 73 long offset = UNSAFE.objectFieldOffset(primitiveField0); 74 if (offset % 8 == 0) { 75 primitiveField0Offset = offset; 76 } else { 77 Field primitiveField1 = DynamicObject.class.getDeclaredField("primitiveField1"); 78 offset = UNSAFE.objectFieldOffset(primitiveField1); 79 assert offset % 8 == 0; 80 primitiveField0Offset = offset; 81 } 82 } catch (NoSuchFieldException | SecurityException e) { 83 throw new AssertionError(e); 84 } 85 } 86 87 public static int unsafeAccessToLongArray(int v, Frame frame) { 88 long[] array = frame.primitiveLocals; 89 int s = UNSAFE.getInt(array, offsetLong1); 90 UNSAFE.putInt(array, offsetLong1, v); 91 UNSAFE.putInt(array, offsetLong2, v); 92 return s + UNSAFE.getInt(array, offsetLong1) + UNSAFE.getInt(array, offsetLong2); 93 } 94 95 @Test 96 public void testUnsafeAccessToLongArray() { 97 StructuredGraph graph = processMethod("unsafeAccessToLongArray"); 98 assertDeepEquals(1, graph.getNodes().filter(RawLoadNode.class).count()); 99 } 100 101 /** 102 * The following value should be less than the default value of 103 * {@link GraalOptions#MaximumEscapeAnalysisArrayLength}. 104 */ 105 private static final int FRAME_SIZE = 16; 106 107 public static long newFrame(long v) { 108 Frame frame = new Frame(FRAME_SIZE); 109 // Testing unsafe accesses with other kinds requires special handling of the initialized 110 // entry kind. 111 UNSAFE.putLong(frame.primitiveLocals, offsetLong1, v); 112 return UNSAFE.getLong(frame.primitiveLocals, offsetLong1); 113 } 114 115 @Test 116 public void testNewFrame() { 117 StructuredGraph graph = processMethod("newFrame"); 118 assertDeepEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count()); 119 assertDeepEquals(0, graph.getNodes().filter(RawLoadNode.class).count()); 120 assertDeepEquals(0, graph.getNodes().filter(RawStoreNode.class).count()); 121 } 122 123 protected StructuredGraph processMethod(final String snippet) { 124 StructuredGraph graph = parseEager(snippet, StructuredGraph.AllowAssumptions.NO); 125 HighTierContext context = getDefaultHighTierContext(); 126 new InliningPhase(new CanonicalizerPhase()).apply(graph, context); 127 new PartialEscapePhase(true, true, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context); 128 return graph; 129 } 130 131 public static double accessDynamicObject(double v) { 132 DynamicObject obj = new DynamicObject(); 133 UNSAFE.putDouble(obj, primitiveField0Offset, v); 134 return UNSAFE.getDouble(obj, primitiveField0Offset); 135 } 136 137 @Test 138 public void testAccessDynamicObject() { 139 StructuredGraph graph = processMethod("accessDynamicObject"); 140 assertDeepEquals(0, graph.getNodes().filter(CommitAllocationNode.class).count()); 141 assertDeepEquals(0, graph.getNodes().filter(RawLoadNode.class).count()); 142 assertDeepEquals(0, graph.getNodes().filter(RawStoreNode.class).count()); 143 } 144 145 }