001/* 002 * Copyright (c) 2012, 2013, 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.inlining; 024 025import jdk.internal.jvmci.code.*; 026import com.oracle.graal.debug.*; 027import com.oracle.graal.debug.Debug.*; 028import jdk.internal.jvmci.meta.*; 029 030import org.junit.*; 031 032import com.oracle.graal.compiler.test.*; 033import com.oracle.graal.graph.*; 034import com.oracle.graal.graphbuilderconf.*; 035import com.oracle.graal.nodes.*; 036import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; 037import com.oracle.graal.phases.*; 038import com.oracle.graal.phases.common.*; 039import com.oracle.graal.phases.common.inlining.*; 040import com.oracle.graal.phases.tiers.*; 041 042public class InliningTest extends GraalCompilerTest { 043 044 @Test 045 public void testInvokeStaticInlining() { 046 assertInlined(getGraph("invokeStaticSnippet", false)); 047 assertInlined(getGraph("invokeStaticOnInstanceSnippet", false)); 048 } 049 050 @SuppressWarnings("all") 051 public static Boolean invokeStaticSnippet(boolean value) { 052 return Boolean.valueOf(value); 053 } 054 055 @SuppressWarnings("all") 056 public static Boolean invokeStaticOnInstanceSnippet(Boolean obj, boolean value) { 057 return obj.valueOf(value); 058 } 059 060 @Test 061 public void testStaticBindableInlining() { 062 assertInlined(getGraph("invokeConstructorSnippet", false)); 063 assertInlined(getGraph("invokeFinalMethodSnippet", false)); 064 assertInlined(getGraph("invokeMethodOnFinalClassSnippet", false)); 065 assertInlined(getGraph("invokeMethodOnStaticFinalFieldSnippet", false)); 066 } 067 068 @Ignore("would need read elimination/EA before inlining") 069 @Test 070 public void testDependentStaticBindableInlining() { 071 assertInlined(getGraph("invokeMethodOnFinalFieldSnippet", false)); 072 assertInlined(getGraph("invokeMethodOnFieldSnippet", false)); 073 } 074 075 @Test 076 public void testStaticBindableInliningIP() { 077 assertManyMethodInfopoints(assertInlined(getGraph("invokeConstructorSnippet", true))); 078 assertManyMethodInfopoints(assertInlined(getGraph("invokeFinalMethodSnippet", true))); 079 assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalClassSnippet", true))); 080 assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnStaticFinalFieldSnippet", true))); 081 } 082 083 @Ignore("would need read elimination/EA before inlining") 084 @Test 085 public void testDependentStaticBindableInliningIP() { 086 assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFinalFieldSnippet", true))); 087 assertManyMethodInfopoints(assertInlined(getGraph("invokeMethodOnFieldSnippet", true))); 088 } 089 090 @SuppressWarnings("all") 091 public static Object invokeConstructorSnippet(int value) { 092 return new SuperClass(value); 093 } 094 095 @SuppressWarnings("all") 096 public static int invokeFinalMethodSnippet(SuperClass superClass, SubClassA subClassA, FinalSubClass finalSubClass) { 097 return superClass.publicFinalMethod() + subClassA.publicFinalMethod() + finalSubClass.publicFinalMethod() + superClass.protectedFinalMethod() + subClassA.protectedFinalMethod() + 098 finalSubClass.protectedFinalMethod(); 099 } 100 101 @SuppressWarnings("all") 102 public static int invokeMethodOnFinalClassSnippet(FinalSubClass finalSubClass) { 103 return finalSubClass.publicFinalMethod() + finalSubClass.publicNotOverriddenMethod() + finalSubClass.publicOverriddenMethod() + finalSubClass.protectedFinalMethod() + 104 finalSubClass.protectedNotOverriddenMethod() + finalSubClass.protectedOverriddenMethod(); 105 } 106 107 @SuppressWarnings("all") 108 public static int invokeMethodOnStaticFinalFieldSnippet() { 109 return StaticFinalFields.NumberStaticFinalField.intValue() + StaticFinalFields.SuperClassStaticFinalField.publicOverriddenMethod() + 110 StaticFinalFields.FinalSubClassStaticFinalField.publicOverriddenMethod() + StaticFinalFields.SingleImplementorStaticFinalField.publicOverriddenMethod() + 111 StaticFinalFields.MultipleImplementorsStaticFinalField.publicOverriddenMethod() + StaticFinalFields.SubClassAStaticFinalField.publicOverriddenMethod() + 112 StaticFinalFields.SubClassBStaticFinalField.publicOverriddenMethod() + StaticFinalFields.SubClassCStaticFinalField.publicOverriddenMethod(); 113 } 114 115 @SuppressWarnings("all") 116 public static int invokeMethodOnFinalFieldSnippet() { 117 FinalFields fields = new FinalFields(); 118 return fields.numberFinalField.intValue() + fields.superClassFinalField.publicOverriddenMethod() + fields.finalSubClassFinalField.publicOverriddenMethod() + 119 fields.singleImplementorFinalField.publicOverriddenMethod() + fields.multipleImplementorsFinalField.publicOverriddenMethod() + 120 fields.subClassAFinalField.publicOverriddenMethod() + fields.subClassBFinalField.publicOverriddenMethod() + fields.subClassCFinalField.publicOverriddenMethod(); 121 } 122 123 @SuppressWarnings("all") 124 public static int invokeMethodOnFieldSnippet() { 125 Fields fields = new Fields(); 126 return fields.numberField.intValue() + fields.superClassField.publicOverriddenMethod() + fields.finalSubClassField.publicOverriddenMethod() + 127 fields.singleImplementorField.publicOverriddenMethod() + fields.multipleImplementorsField.publicOverriddenMethod() + fields.subClassAField.publicOverriddenMethod() + 128 fields.subClassBField.publicOverriddenMethod() + fields.subClassCField.publicOverriddenMethod(); 129 } 130 131 public interface Attributes { 132 133 int getLength(); 134 } 135 136 public class NullAttributes implements Attributes { 137 138 @Override 139 public int getLength() { 140 return 0; 141 } 142 143 } 144 145 public class TenAttributes implements Attributes { 146 147 @Override 148 public int getLength() { 149 return 10; 150 } 151 152 } 153 154 public int getAttributesLength(Attributes a) { 155 return a.getLength(); 156 } 157 158 @Test 159 public void testGuardedInline() { 160 NullAttributes nullAttributes = new NullAttributes(); 161 for (int i = 0; i < 10000; i++) { 162 getAttributesLength(nullAttributes); 163 } 164 getAttributesLength(new TenAttributes()); 165 166 test("getAttributesLength", nullAttributes); 167 test("getAttributesLength", (Object) null); 168 } 169 170 @Test 171 public void testClassHierarchyAnalysis() { 172 assertInlined(getGraph("invokeLeafClassMethodSnippet", false)); 173 assertInlined(getGraph("invokeConcreteMethodSnippet", false)); 174 assertInlined(getGraph("invokeSingleImplementorInterfaceSnippet", false)); 175 // assertInlined(getGraph("invokeConcreteInterfaceMethodSnippet", false)); 176 177 assertNotInlined(getGraph("invokeOverriddenPublicMethodSnippet", false)); 178 assertNotInlined(getGraph("invokeOverriddenProtectedMethodSnippet", false)); 179 assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", false)); 180 } 181 182 @Test 183 public void testClassHierarchyAnalysisIP() { 184 assertManyMethodInfopoints(assertInlined(getGraph("invokeLeafClassMethodSnippet", true))); 185 assertManyMethodInfopoints(assertInlined(getGraph("invokeConcreteMethodSnippet", true))); 186 assertManyMethodInfopoints(assertInlined(getGraph("invokeSingleImplementorInterfaceSnippet", true))); 187 //@formatter:off 188 // assertInlineInfopoints(assertInlined(getGraph("invokeConcreteInterfaceMethodSnippet", true))); 189 //@formatter:on 190 191 assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenPublicMethodSnippet", true))); 192 assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenProtectedMethodSnippet", true))); 193 assertFewMethodInfopoints(assertNotInlined(getGraph("invokeOverriddenInterfaceMethodSnippet", true))); 194 } 195 196 @SuppressWarnings("all") 197 public static int invokeLeafClassMethodSnippet(SubClassA subClassA) { 198 return subClassA.publicFinalMethod() + subClassA.publicNotOverriddenMethod() + subClassA.publicOverriddenMethod(); 199 } 200 201 @SuppressWarnings("all") 202 public static int invokeConcreteMethodSnippet(SuperClass superClass) { 203 return superClass.publicNotOverriddenMethod() + superClass.protectedNotOverriddenMethod(); 204 } 205 206 @SuppressWarnings("all") 207 public static int invokeSingleImplementorInterfaceSnippet(SingleImplementorInterface testInterface) { 208 return testInterface.publicNotOverriddenMethod() + testInterface.publicOverriddenMethod(); 209 } 210 211 @SuppressWarnings("all") 212 public static int invokeConcreteInterfaceMethodSnippet(MultipleImplementorsInterface testInterface) { 213 return testInterface.publicNotOverriddenMethod(); 214 } 215 216 @SuppressWarnings("all") 217 public static int invokeOverriddenInterfaceMethodSnippet(MultipleImplementorsInterface testInterface) { 218 return testInterface.publicOverriddenMethod(); 219 } 220 221 @SuppressWarnings("all") 222 public static int invokeOverriddenPublicMethodSnippet(SuperClass superClass) { 223 return superClass.publicOverriddenMethod(); 224 } 225 226 @SuppressWarnings("all") 227 public static int invokeOverriddenProtectedMethodSnippet(SuperClass superClass) { 228 return superClass.protectedOverriddenMethod(); 229 } 230 231 private StructuredGraph getGraph(final String snippet, final boolean eagerInfopointMode) { 232 try (Scope s = Debug.scope("InliningTest", new DebugDumpScope(snippet))) { 233 ResolvedJavaMethod method = getResolvedJavaMethod(snippet); 234 StructuredGraph graph = eagerInfopointMode ? parseDebug(method, AllowAssumptions.YES) : parseEager(method, AllowAssumptions.YES); 235 PhaseSuite<HighTierContext> graphBuilderSuite = eagerInfopointMode ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault(getDefaultGraphBuilderPlugins())) 236 : getDefaultGraphBuilderSuite(); 237 HighTierContext context = new HighTierContext(getProviders(), graphBuilderSuite, OptimisticOptimizations.ALL); 238 Debug.dump(graph, "Graph"); 239 new CanonicalizerPhase().apply(graph, context); 240 new InliningPhase(new CanonicalizerPhase()).apply(graph, context); 241 Debug.dump(graph, "Graph"); 242 new CanonicalizerPhase().apply(graph, context); 243 new DeadCodeEliminationPhase().apply(graph); 244 return graph; 245 } catch (Throwable e) { 246 throw Debug.handle(e); 247 } 248 } 249 250 private static StructuredGraph assertInlined(StructuredGraph graph) { 251 return assertNotInGraph(graph, Invoke.class); 252 } 253 254 private static StructuredGraph assertNotInlined(StructuredGraph graph) { 255 return assertInGraph(graph, Invoke.class); 256 } 257 258 private static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) { 259 for (Node node : graph.getNodes()) { 260 if (clazz.isInstance(node)) { 261 fail(node.toString()); 262 } 263 } 264 return graph; 265 } 266 267 private static StructuredGraph assertInGraph(StructuredGraph graph, Class<?> clazz) { 268 for (Node node : graph.getNodes()) { 269 if (clazz.isInstance(node)) { 270 return graph; 271 } 272 } 273 fail("Graph does not contain a node of class " + clazz.getName()); 274 return graph; 275 } 276 277 private static int[] countMethodInfopoints(StructuredGraph graph) { 278 int start = 0; 279 int end = 0; 280 for (FullInfopointNode ipn : graph.getNodes().filter(FullInfopointNode.class)) { 281 if (ipn.getReason() == InfopointReason.METHOD_START) { 282 ++start; 283 } else if (ipn.getReason() == InfopointReason.METHOD_END) { 284 ++end; 285 } 286 } 287 return new int[]{start, end}; 288 } 289 290 private static StructuredGraph assertManyMethodInfopoints(StructuredGraph graph) { 291 int[] counts = countMethodInfopoints(graph); 292 if (counts[0] <= 1 || counts[1] <= 1) { 293 fail(String.format("Graph contains too few required method boundary infopoints: %d starts, %d ends.", counts[0], counts[1])); 294 } 295 return graph; 296 } 297 298 private static StructuredGraph assertFewMethodInfopoints(StructuredGraph graph) { 299 int[] counts = countMethodInfopoints(graph); 300 if (counts[0] > 1 || counts[1] > 1) { 301 fail(String.format("Graph contains too many method boundary infopoints: %d starts, %d ends.", counts[0], counts[1])); 302 } 303 return graph; 304 } 305 306 // some interfaces and classes for testing 307 private interface MultipleImplementorsInterface { 308 309 int publicNotOverriddenMethod(); 310 311 int publicOverriddenMethod(); 312 } 313 314 private interface SingleImplementorInterface { 315 316 int publicNotOverriddenMethod(); 317 318 int publicOverriddenMethod(); 319 } 320 321 private static class SuperClass implements MultipleImplementorsInterface { 322 323 protected int value; 324 325 public SuperClass(int value) { 326 this.value = value; 327 } 328 329 public int publicNotOverriddenMethod() { 330 return value; 331 } 332 333 public int publicOverriddenMethod() { 334 return value; 335 } 336 337 protected int protectedNotOverriddenMethod() { 338 return value; 339 } 340 341 protected int protectedOverriddenMethod() { 342 return value; 343 } 344 345 public final int publicFinalMethod() { 346 return value + 255; 347 } 348 349 protected final int protectedFinalMethod() { 350 return value + 255; 351 } 352 } 353 354 private static class SubClassA extends SuperClass implements SingleImplementorInterface { 355 356 public SubClassA(int value) { 357 super(value); 358 } 359 360 @Override 361 public int publicOverriddenMethod() { 362 return value + 2; 363 } 364 365 @Override 366 protected int protectedOverriddenMethod() { 367 return value * 2; 368 } 369 } 370 371 private static class SubClassB extends SuperClass { 372 373 public SubClassB(int value) { 374 super(value); 375 } 376 377 @Override 378 public int publicOverriddenMethod() { 379 return value + 3; 380 } 381 382 @Override 383 protected int protectedOverriddenMethod() { 384 return value * 3; 385 } 386 } 387 388 private static class SubClassC extends SuperClass { 389 390 public SubClassC(int value) { 391 super(value); 392 } 393 394 @Override 395 public int publicOverriddenMethod() { 396 return value + 4; 397 } 398 399 @Override 400 protected int protectedOverriddenMethod() { 401 return value * 4; 402 } 403 } 404 405 private static final class FinalSubClass extends SuperClass { 406 407 public FinalSubClass(int value) { 408 super(value); 409 } 410 411 @Override 412 public int publicOverriddenMethod() { 413 return value + 5; 414 } 415 416 @Override 417 protected int protectedOverriddenMethod() { 418 return value * 5; 419 } 420 } 421 422 private static final class StaticFinalFields { 423 424 private static final Number NumberStaticFinalField = new Integer(1); 425 private static final SuperClass SuperClassStaticFinalField = new SubClassA(2); 426 private static final FinalSubClass FinalSubClassStaticFinalField = new FinalSubClass(3); 427 private static final SingleImplementorInterface SingleImplementorStaticFinalField = new SubClassA(4); 428 private static final MultipleImplementorsInterface MultipleImplementorsStaticFinalField = new SubClassC(5); 429 private static final SubClassA SubClassAStaticFinalField = new SubClassA(6); 430 private static final SubClassB SubClassBStaticFinalField = new SubClassB(7); 431 private static final SubClassC SubClassCStaticFinalField = new SubClassC(8); 432 } 433 434 private static final class FinalFields { 435 436 private final Number numberFinalField = new Integer(1); 437 private final SuperClass superClassFinalField = new SubClassA(2); 438 private final FinalSubClass finalSubClassFinalField = new FinalSubClass(3); 439 private final SingleImplementorInterface singleImplementorFinalField = new SubClassA(4); 440 private final MultipleImplementorsInterface multipleImplementorsFinalField = new SubClassC(5); 441 private final SubClassA subClassAFinalField = new SubClassA(6); 442 private final SubClassB subClassBFinalField = new SubClassB(7); 443 private final SubClassC subClassCFinalField = new SubClassC(8); 444 } 445 446 private static final class Fields { 447 448 private Number numberField = new Integer(1); 449 private SuperClass superClassField = new SubClassA(2); 450 private FinalSubClass finalSubClassField = new FinalSubClass(3); 451 private SingleImplementorInterface singleImplementorField = new SubClassA(4); 452 private MultipleImplementorsInterface multipleImplementorsField = new SubClassC(5); 453 private SubClassA subClassAField = new SubClassA(6); 454 private SubClassB subClassBField = new SubClassB(7); 455 private SubClassC subClassCField = new SubClassC(8); 456 } 457}