changeset 19892:08233b1ae932

Truffle: try to inline method handle invocations in FastPE
author Andreas Woess <andreas.woess@oracle.com>
date Tue, 17 Mar 2015 15:39:46 +0100
parents aa66d0a6f9dc
children 4b6a65cb8ecd
files graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SimplePartialEvaluationTest.java graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/LambdaTestNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java
diffstat 3 files changed, 105 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SimplePartialEvaluationTest.java	Tue Mar 17 15:36:09 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SimplePartialEvaluationTest.java	Tue Mar 17 15:39:46 2015 +0100
@@ -136,4 +136,11 @@
         assertPartialEvalNoInvokes(rootNode);
         assertPartialEvalEquals("constant42", rootNode);
     }
+
+    @Test
+    public void lambda() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new LambdaTestNode();
+        assertPartialEvalEquals("constant42", new RootTestNode(fd, "constantValue", result));
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/LambdaTestNode.java	Tue Mar 17 15:39:46 2015 +0100
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, 2015, 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 com.oracle.graal.truffle.test.nodes;
+
+import java.util.function.*;
+
+import com.oracle.truffle.api.frame.*;
+
+public class LambdaTestNode extends AbstractTestNode {
+    @Override
+    public int execute(VirtualFrame frame) {
+        return lambda(() -> 42);
+    }
+
+    private static int lambda(Supplier<Integer> supplier) {
+        return supplier.get();
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Mar 17 15:36:09 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Mar 17 15:39:46 2015 +0100
@@ -28,7 +28,9 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.Assumptions.AssumptionResult;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.MethodHandleAccessProvider.IntrinsicMethod;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -48,6 +50,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
@@ -199,6 +202,13 @@
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
+            IntrinsicMethod intrinsicMethod = builder.getConstantReflection().getMethodHandleAccess().lookupMethodHandleIntrinsic(original);
+            if (intrinsicMethod != null) {
+                InlineInfo inlineInfo = getMethodHandleIntrinsicInlineInfo(builder, arguments, intrinsicMethod);
+                if (inlineInfo != null) {
+                    return inlineInfo;
+                }
+            }
             if (replacements != null && (replacements.getMethodSubstitutionMethod(original) != null || replacements.getMacroSubstitution(original) != null)) {
                 return null;
             }
@@ -233,6 +243,56 @@
                 inlining.pop();
             }
         }
+
+        private InlineInfo getMethodHandleIntrinsicInlineInfo(GraphBuilderContext builder, ValueNode[] arguments, IntrinsicMethod intrinsicMethod) {
+            ResolvedJavaMethod targetMethod = null;
+            switch (intrinsicMethod) {
+                case INVOKE_BASIC:
+                    ValueNode methodHandleNode = arguments[0];
+                    if (methodHandleNode.isConstant()) {
+                        targetMethod = builder.getConstantReflection().getMethodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true);
+                    }
+                    break;
+                case LINK_TO_STATIC:
+                case LINK_TO_SPECIAL:
+                case LINK_TO_VIRTUAL:
+                case LINK_TO_INTERFACE:
+                    ValueNode memberNameNode = arguments[arguments.length - 1];
+                    if (memberNameNode.isConstant()) {
+                        targetMethod = builder.getConstantReflection().getMethodHandleAccess().resolveLinkToTarget(memberNameNode.asJavaConstant());
+                    }
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+            if (targetMethod != null) {
+                // TODO maybe cast arguments
+
+                if (targetMethod.canBeStaticallyBound()) {
+                    return new InlineInfo(targetMethod, false, false);
+                }
+
+                // Try to get the most accurate receiver type
+                if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
+                    ResolvedJavaType receiverType = StampTool.typeOrNull(arguments[0].stamp());
+                    if (receiverType != null) {
+                        AssumptionResult<ResolvedJavaMethod> concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
+                        if (concreteMethod != null) {
+                            builder.getAssumptions().record(concreteMethod);
+                            return new InlineInfo(concreteMethod.getResult(), false, false);
+                        }
+                    }
+                } else {
+                    AssumptionResult<ResolvedJavaMethod> concreteMethod = targetMethod.getDeclaringClass().findUniqueConcreteMethod(targetMethod);
+                    if (concreteMethod != null) {
+                        builder.getAssumptions().record(concreteMethod);
+                        return new InlineInfo(concreteMethod.getResult(), false, false);
+                    }
+                }
+            }
+
+            return null;
+        }
     }
 
     private class PELoopExplosionPlugin implements LoopExplosionPlugin {