001/* 002 * Copyright (c) 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.replacements.test; 024 025import java.util.function.*; 026 027import jdk.internal.jvmci.meta.*; 028 029import org.junit.*; 030 031import com.oracle.graal.api.replacements.*; 032import com.oracle.graal.api.runtime.*; 033import com.oracle.graal.compiler.test.*; 034import com.oracle.graal.graph.Node.ConstantNodeParameter; 035import com.oracle.graal.graph.Node.NodeIntrinsic; 036import com.oracle.graal.nodes.*; 037import com.oracle.graal.nodes.spi.*; 038import com.oracle.graal.runtime.*; 039 040/** 041 * Tests for expected behavior when parsing snippets and intrinsics. 042 */ 043public class ReplacementsParseTest extends GraalCompilerTest { 044 045 private static final Object THROW_EXCEPTION_MARKER = new Object() { 046 @Override 047 public String toString() { 048 return "THROW_EXCEPTION_MARKER"; 049 } 050 }; 051 052 static class TestMethods { 053 static double next(double v) { 054 return Math.nextAfter(v, 1.0); 055 } 056 057 static double next2(double v) { 058 return Math.nextAfter(v, 1.0); 059 } 060 061 static double nextAfter(double x, double d) { 062 return Math.nextAfter(x, d); 063 } 064 065 static String stringize(Object obj) { 066 String res = String.valueOf(obj); 067 if (res.equals(THROW_EXCEPTION_MARKER.toString())) { 068 // Tests exception throwing from partial intrinsification 069 throw new RuntimeException("ex: " + obj); 070 } 071 return res; 072 } 073 074 static String identity(String s) { 075 return s; 076 } 077 } 078 079 @ClassSubstitution(TestMethods.class) 080 static class TestMethodsSubstitutions { 081 082 @MethodSubstitution(isStatic = true) 083 static double nextAfter(double x, double d) { 084 double xx = (x == -0.0 ? 0.0 : x); 085 return Math.nextAfter(xx, d); 086 } 087 088 /** 089 * Tests partial intrinsification. 090 */ 091 @MethodSubstitution 092 static String stringize(Object obj) { 093 if (obj != null && obj.getClass() == String.class) { 094 return asNonNullString(obj); 095 } else { 096 // A recursive call denotes exiting/deoptimizing 097 // out of the partial intrinsification to the 098 // slow/uncommon case. 099 return stringize(obj); 100 } 101 } 102 103 public static String asNonNullString(Object object) { 104 return asNonNullStringIntrinsic(object, String.class, true, true); 105 } 106 107 @NodeIntrinsic(PiNode.class) 108 private static native String asNonNullStringIntrinsic(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull); 109 110 /** 111 * Tests that non-capturing lambdas are folded away. 112 */ 113 @MethodSubstitution 114 static String identity(String value) { 115 return apply(s -> s, value); 116 } 117 118 private static String apply(Function<String, String> f, String value) { 119 return f.apply(value); 120 } 121 } 122 123 private static boolean substitutionsInstalled; 124 125 public ReplacementsParseTest() { 126 if (!substitutionsInstalled) { 127 Replacements replacements = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getProviders().getReplacements(); 128 replacements.registerSubstitutions(TestMethods.class, TestMethodsSubstitutions.class); 129 substitutionsInstalled = true; 130 } 131 } 132 133 /** 134 * Ensure that calling the original method from the substitution binds correctly. 135 */ 136 @Test 137 public void test1() { 138 test("test1Snippet", 1.0); 139 } 140 141 public double test1Snippet(double d) { 142 return TestMethods.next(d); 143 } 144 145 /** 146 * Ensure that calling the substitution method binds to the original method properly. 147 */ 148 @Test 149 public void test2() { 150 test("test2Snippet", 1.0); 151 } 152 153 public double test2Snippet(double d) { 154 return TestMethods.next2(d); 155 } 156 157 /** 158 * Ensure that substitution methods with assertions in them don't complain when the exception 159 * constructor is deleted. 160 */ 161 162 @Test 163 public void testNextAfter() { 164 double[] inArray = new double[1024]; 165 double[] outArray = new double[1024]; 166 for (int i = 0; i < inArray.length; i++) { 167 inArray[i] = -0.0; 168 } 169 test("doNextAfter", inArray, outArray); 170 } 171 172 public void doNextAfter(double[] outArray, double[] inArray) { 173 for (int i = 0; i < inArray.length; i++) { 174 double direction = (i & 1) == 0 ? Double.POSITIVE_INFINITY : -Double.NEGATIVE_INFINITY; 175 outArray[i] = TestMethods.nextAfter(inArray[i], direction); 176 } 177 } 178 179 @Test 180 public void testCallStringize() { 181 test("callStringize", "a string"); 182 test("callStringize", THROW_EXCEPTION_MARKER); 183 test("callStringize", Boolean.TRUE); 184 } 185 186 public static Object callStringize(Object obj) { 187 return TestMethods.stringize(obj); 188 } 189 190 @Test 191 public void testRootCompileStringize() { 192 ResolvedJavaMethod method = getResolvedJavaMethod(TestMethods.class, "stringize"); 193 test(method, null, "a string"); 194 test(method, null, Boolean.TRUE); 195 test(method, null, THROW_EXCEPTION_MARKER); 196 } 197 198 @Test 199 public void testLambda() { 200 test("callLambda", (String) null); 201 test("callLambda", "a string"); 202 } 203 204 public static String callLambda(String value) { 205 return TestMethods.identity(value); 206 } 207}