changeset 15481:09d721bcffe2

Introduce API for lookup of VM-internals of method handles
author Christian Wimmer <christian.wimmer@oracle.com>
date Fri, 02 May 2014 11:04:51 -0700
parents 1a7ebcf3ae22
children a250a512434d 01a8820c1228
files graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodHandleAccessProvider.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleInvokeBasicNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToInterfaceNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToSpecialNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToStaticNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToVirtualNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java
diffstat 16 files changed, 553 insertions(+), 548 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodHandleAccessProvider.java	Fri May 02 11:04:51 2014 -0700
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, 2014, 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.api.replacements;
+
+import java.lang.invoke.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Interface to access the internals of the {@link MethodHandle} implementation of the VM. An
+ * implementation of this interface is usually required to access non-public classes, methods, and
+ * fields of {@link MethodHandle}, i.e., data that is not standardized by the Java specification.
+ */
+public interface MethodHandleAccessProvider {
+
+    /**
+     * Identification for methods defined on the class {@link MethodHandle} that are processed by
+     * the {@link MethodHandleAccessProvider}.
+     */
+    public enum IntrinsicMethod {
+        /** The method {@code MethodHandle.invokeBasic}. */
+        INVOKE_BASIC,
+        /** The method {@code MethodHandle.linkToStatic}. */
+        LINK_TO_STATIC,
+        /** The method {@code MethodHandle.linkToSpecial}. */
+        LINK_TO_SPECIAL,
+        /** The method {@code MethodHandle.linkToVirtual}. */
+        LINK_TO_VIRTUAL,
+        /** The method {@code MethodHandle.linkToInterface}. */
+        LINK_TO_INTERFACE
+    }
+
+    /**
+     * Returns the method handle method intrinsic identifier for the provided method, or
+     * {@code null} if the method is not an intrinsic processed by this interface.
+     */
+    IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method);
+
+    /**
+     * Resolves the invocation target for an invocation of {@link IntrinsicMethod#INVOKE_BASIC
+     * MethodHandle.invokeBasic} with the given constant receiver {@link MethodHandle}. Returns
+     * {@code null} if the invocation target is not available at this time.
+     * <p>
+     * The first invocations of a method handle can use an interpreter to lookup the actual invoked
+     * method; frequently executed method handles can use Java bytecode generation to avoid the
+     * interpreter overhead. If the parameter forceBytecodeGeneration is set to true, the VM should
+     * try to generate bytecodes before this method returns.
+     */
+    ResolvedJavaMethod resolveInvokeBasicTarget(Constant methodHandle, boolean forceBytecodeGeneration);
+
+    /**
+     * Resolves the invocation target for an invocation of a {@code MethodHandle.linkTo*} method
+     * with the given constant member name. The member name is the last parameter of the
+     * {@code linkTo*} method. Returns {@code null} if the invocation target is not available at
+     * this time.
+     */
+    ResolvedJavaMethod resolveLinkToTarget(Constant memberName);
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri May 02 17:14:09 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri May 02 11:04:51 2014 -0700
@@ -113,7 +113,9 @@
         Replacements replacements = createReplacements(runtime, assumptions, p, snippetReflection);
         HotSpotDisassemblerProvider disassembler = createDisassembler(runtime);
         HotSpotSuitesProvider suites = createSuites(runtime);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
+        HotSpotMethodHandleAccessProvider methodHandleAccess = new HotSpotMethodHandleAccessProvider();
+        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection,
+                        methodHandleAccess);
 
         return createBackend(runtime, providers);
     }
@@ -189,15 +191,15 @@
         } else {
             /*
              * System V Application Binary Interface, AMD64 Architecture Processor Supplement
-             * 
+             *
              * Draft Version 0.96
-             * 
+             *
              * http://www.uclibc.org/docs/psABI-x86_64.pdf
-             * 
+             *
              * 3.2.1
-             * 
+             *
              * ...
-             * 
+             *
              * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
              * through %r15 "belong" to the calling function and the called function is required to
              * preserve their values. In other words, a called function must preserve these
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Fri May 02 17:14:09 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java	Fri May 02 11:04:51 2014 -0700
@@ -57,7 +57,8 @@
         Replacements replacements = new HSAILHotSpotReplacementsImpl(p, host.getSnippetReflection(), assumptions, codeCache.getTarget(), host.getReplacements());
         HotSpotDisassemblerProvider disassembler = host.getDisassembler();
         SuitesProvider suites = new HotSpotSuitesProvider(runtime);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection());
+        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection(),
+                        host.getMethodHandleAccess());
 
         // pass registers info down to ReplacementsUtil (maybe a better way to do this?)
         HSAILHotSpotReplacementsUtil.initialize(providers.getRegisters());
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java	Fri May 02 17:14:09 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java	Fri May 02 11:04:51 2014 -0700
@@ -47,7 +47,8 @@
         HotSpotDisassemblerProvider disassembler = host.getDisassembler();
         SuitesProvider suites = new DefaultSuitesProvider();
         HotSpotRegistersProvider registers = new HotSpotRegisters(PTX.tid, Register.None, Register.None);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection());
+        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection(),
+                        host.getMethodHandleAccess());
         return new PTXHotSpotBackend(runtime, providers);
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri May 02 17:14:09 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri May 02 11:04:51 2014 -0700
@@ -64,7 +64,9 @@
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), assumptions, target);
         HotSpotDisassemblerProvider disassembler = new HotSpotDisassemblerProvider(runtime);
         HotSpotSuitesProvider suites = new HotSpotSuitesProvider(runtime);
-        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
+        HotSpotMethodHandleAccessProvider methodHandleAccess = new HotSpotMethodHandleAccessProvider();
+        HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection,
+                        methodHandleAccess);
 
         return new SPARCHotSpotBackend(runtime, providers);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Fri May 02 17:14:09 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Fri May 02 11:04:51 2014 -0700
@@ -368,6 +368,8 @@
             return (T) this;
         } else if (clazz == SnippetReflectionProvider.class) {
             return (T) getHostProviders().getSnippetReflection();
+        } else if (clazz == MethodHandleAccessProvider.class) {
+            return (T) getHostProviders().getMethodHandleAccess();
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri May 02 17:14:09 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri May 02 11:04:51 2014 -0700
@@ -86,16 +86,14 @@
         HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
         int intrinsicId = hsMethod.intrinsicId();
         if (intrinsicId != 0) {
-            if (intrinsicId == config.vmIntrinsicInvokeBasic) {
-                return MethodHandleInvokeBasicNode.class;
-            } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
-                return MethodHandleLinkToInterfaceNode.class;
-            } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
-                return MethodHandleLinkToSpecialNode.class;
-            } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
-                return MethodHandleLinkToStaticNode.class;
-            } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
-                return MethodHandleLinkToVirtualNode.class;
+            /*
+             * The methods of MethodHandle that need substitution are signature-polymorphic, i.e.,
+             * the VM replicates them for every signature that they are actually used for.
+             * Therefore, we cannot use the usual annotation-driven mechanism to define the
+             * substitution.
+             */
+            if (MethodHandleNode.lookupMethodHandleIntrinsic(method) != null) {
+                return MethodHandleNode.class;
             }
         }
         return super.getMacroSubstitution(method);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java	Fri May 02 11:04:51 2014 -0700
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014, 2014, 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.hotspot.meta;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.hotspot.*;
+
+public class HotSpotMethodHandleAccessProvider implements MethodHandleAccessProvider {
+
+    /**
+     * Lazy initialization to break class initialization cycle. Field and method lookup is only
+     * possible after the {@link HotSpotGraalRuntime} is fully initialized.
+     */
+    static class LazyInitialization {
+        static final ResolvedJavaField methodHandleFormField;
+        static final ResolvedJavaField lambdaFormVmentryField;
+        static final ResolvedJavaMethod lambdaFormCompileToBytecodeMethod;
+        static final ResolvedJavaField memberNameVmtargetField;
+
+        /**
+         * Search for an instance field with the given name in a class.
+         *
+         * @param className name of the class to search in
+         * @param fieldName name of the field to be searched
+         * @return resolved java field
+         * @throws ClassNotFoundException
+         */
+        private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException {
+            Class<?> clazz = Class.forName(className);
+            ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz);
+            ResolvedJavaField[] fields = type.getInstanceFields(false);
+            for (ResolvedJavaField field : fields) {
+                if (field.getName().equals(fieldName)) {
+                    return field;
+                }
+            }
+            return null;
+        }
+
+        private static ResolvedJavaMethod findMethodInClass(String className, String methodName) throws ClassNotFoundException {
+            Class<?> clazz = Class.forName(className);
+            ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz);
+            ResolvedJavaMethod result = null;
+            for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
+                if (method.getName().equals(methodName)) {
+                    assert result == null : "more than one method found: " + className + "." + methodName;
+                    result = method;
+                }
+            }
+            assert result != null : "method not found: " + className + "." + methodName;
+            return result;
+        }
+
+        static {
+            try {
+                methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form");
+                lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry");
+                lambdaFormCompileToBytecodeMethod = findMethodInClass("java.lang.invoke.LambdaForm", "compileToBytecode");
+                memberNameVmtargetField = findFieldInClass("java.lang.invoke.MemberName", "vmtarget");
+            } catch (Throwable ex) {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    @Override
+    public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) {
+        int intrinsicId = ((HotSpotResolvedJavaMethod) method).intrinsicId();
+        if (intrinsicId != 0) {
+            HotSpotVMConfig config = runtime().getConfig();
+            if (intrinsicId == config.vmIntrinsicInvokeBasic) {
+                return IntrinsicMethod.INVOKE_BASIC;
+            } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
+                return IntrinsicMethod.LINK_TO_INTERFACE;
+            } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
+                return IntrinsicMethod.LINK_TO_SPECIAL;
+            } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
+                return IntrinsicMethod.LINK_TO_STATIC;
+            } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
+                return IntrinsicMethod.LINK_TO_VIRTUAL;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public ResolvedJavaMethod resolveInvokeBasicTarget(Constant methodHandle, boolean forceBytecodeGeneration) {
+        if (methodHandle.isNull()) {
+            return null;
+        }
+
+        /* Load non-public field: LambdaForm MethodHandle.form */
+        Constant lambdaForm = LazyInitialization.methodHandleFormField.readValue(methodHandle);
+        if (lambdaForm.isNull()) {
+            return null;
+        }
+
+        Constant memberName;
+        if (forceBytecodeGeneration) {
+            /* Invoke non-public method: MemberName LambdaForm.compileToBytecode() */
+            memberName = LazyInitialization.lambdaFormCompileToBytecodeMethod.invoke(lambdaForm, new Constant[0]);
+        } else {
+            /* Load non-public field: MemberName LambdaForm.vmentry */
+            memberName = LazyInitialization.lambdaFormVmentryField.readValue(lambdaForm);
+        }
+        return getTargetMethod(memberName);
+    }
+
+    @Override
+    public ResolvedJavaMethod resolveLinkToTarget(Constant memberName) {
+        return getTargetMethod(memberName);
+    }
+
+    /**
+     * Returns the {@link ResolvedJavaMethod} for the vmtarget of a java.lang.invoke.MemberName.
+     */
+    private static ResolvedJavaMethod getTargetMethod(Constant memberName) {
+        if (memberName.isNull()) {
+            return null;
+        }
+
+        /* Load injected field: JVM_Method* MemberName.vmtarget */
+        Constant vmtarget = LazyInitialization.memberNameVmtargetField.readValue(memberName);
+        /* Create a method from the vmtarget method pointer. */
+        return HotSpotResolvedJavaMethod.fromMetaspace(vmtarget.asLong());
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Fri May 02 17:14:09 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java	Fri May 02 11:04:51 2014 -0700
@@ -38,15 +38,17 @@
     private final SuitesProvider suites;
     private final HotSpotRegistersProvider registers;
     private final SnippetReflectionProvider snippetReflection;
+    private final HotSpotMethodHandleAccessProvider methodHandleAccess;
 
     public HotSpotProviders(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls,
                     LoweringProvider lowerer, Replacements replacements, HotSpotDisassemblerProvider disassembler, SuitesProvider suites, HotSpotRegistersProvider registers,
-                    SnippetReflectionProvider snippetReflection) {
+                    SnippetReflectionProvider snippetReflection, HotSpotMethodHandleAccessProvider methodHandleAccess) {
         super(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements);
         this.disassembler = disassembler;
         this.suites = suites;
         this.registers = registers;
         this.snippetReflection = snippetReflection;
+        this.methodHandleAccess = methodHandleAccess;
     }
 
     @Override
@@ -79,4 +81,8 @@
     public SnippetReflectionProvider getSnippetReflection() {
         return snippetReflection;
     }
+
+    public HotSpotMethodHandleAccessProvider getMethodHandleAccess() {
+        return methodHandleAccess;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java	Fri May 02 17:14:09 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-/*
- * Copyright (c) 2013, 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.hotspot.replacements;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * Common base class for method handle invoke nodes.
- */
-public abstract class AbstractMethodHandleNode extends MacroNode implements Canonicalizable {
-
-    private static final ResolvedJavaField methodHandleFormField;
-    private static final ResolvedJavaField lambdaFormVmentryField;
-    private static final ResolvedJavaField memberNameClazzField;
-    private static final ResolvedJavaField memberNameVmtargetField;
-
-    // Replacement method data
-    private ResolvedJavaMethod replacementTargetMethod;
-    private JavaType replacementReturnType;
-    @Input private final NodeInputList<ValueNode> replacementArguments;
-
-    /**
-     * Search for an instance field with the given name in a class.
-     *
-     * @param className name of the class to search in
-     * @param fieldName name of the field to be searched
-     * @return resolved java field
-     * @throws ClassNotFoundException
-     */
-    private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException {
-        Class<?> clazz = Class.forName(className);
-        ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz);
-        ResolvedJavaField[] fields = type.getInstanceFields(false);
-        for (ResolvedJavaField field : fields) {
-            if (field.getName().equals(fieldName)) {
-                return field;
-            }
-        }
-        return null;
-    }
-
-    static {
-        try {
-            methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form");
-            lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry");
-            memberNameClazzField = findFieldInClass("java.lang.invoke.MemberName", "clazz");
-            memberNameVmtargetField = findFieldInClass("java.lang.invoke.MemberName", "vmtarget");
-        } catch (ClassNotFoundException | SecurityException ex) {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
-
-    public AbstractMethodHandleNode(Invoke invoke) {
-        super(invoke);
-
-        // See if we need to save some replacement method data.
-        CallTargetNode callTarget = invoke.callTarget();
-        if (callTarget instanceof SelfReplacingMethodCallTargetNode) {
-            SelfReplacingMethodCallTargetNode selfReplacingMethodCallTargetNode = (SelfReplacingMethodCallTargetNode) callTarget;
-            replacementTargetMethod = selfReplacingMethodCallTargetNode.replacementTargetMethod();
-            replacementReturnType = selfReplacingMethodCallTargetNode.replacementReturnType();
-            replacementArguments = selfReplacingMethodCallTargetNode.replacementArguments();
-        } else {
-            // NodeInputList can't be null.
-            replacementArguments = new NodeInputList<>(this);
-        }
-    }
-
-    /**
-     * Get the receiver of a MethodHandle.invokeBasic call.
-     *
-     * @return the receiver argument node
-     */
-    private ValueNode getReceiver() {
-        return arguments.first();
-    }
-
-    /**
-     * Get the MemberName argument of a MethodHandle.linkTo* call.
-     *
-     * @return the MemberName argument node (which is the last argument)
-     */
-    private ValueNode getMemberName() {
-        return arguments.last();
-    }
-
-    /**
-     * Used from {@link MethodHandleInvokeBasicNode} to get the target {@link InvokeNode} if the
-     * method handle receiver is constant.
-     *
-     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
-     */
-    protected InvokeNode getInvokeBasicTarget() {
-        ValueNode methodHandleNode = getReceiver();
-        if (methodHandleNode.isConstant() && !methodHandleNode.isNullConstant()) {
-            // Get the data we need from MethodHandle.LambdaForm.MemberName
-            Constant methodHandle = methodHandleNode.asConstant();
-            Constant lambdaForm = methodHandleFormField.readValue(methodHandle);
-            Constant memberName = lambdaFormVmentryField.readValue(lambdaForm);
-            return getTargetInvokeNode(memberName);
-        }
-        return null;
-    }
-
-    /**
-     * Used from {@link MethodHandleLinkToStaticNode}, {@link MethodHandleLinkToSpecialNode},
-     * {@link MethodHandleLinkToVirtualNode}, and {@link MethodHandleLinkToInterfaceNode} to get the
-     * target {@link InvokeNode} if the member name argument is constant.
-     *
-     * @return invoke node for the member name target
-     */
-    protected InvokeNode getLinkToTarget() {
-        ValueNode memberNameNode = getMemberName();
-        if (memberNameNode.isConstant() && !memberNameNode.isNullConstant()) {
-            Constant memberName = memberNameNode.asConstant();
-            return getTargetInvokeNode(memberName);
-        }
-        return null;
-    }
-
-    /**
-     * Helper function to get the {@link InvokeNode} for the vmtarget of a
-     * java.lang.invoke.MemberName.
-     *
-     * @param memberName constant member name node
-     * @return invoke node for the member name target
-     */
-    private InvokeNode getTargetInvokeNode(Constant memberName) {
-        // Get the data we need from MemberName
-        Constant clazz = memberNameClazzField.readValue(memberName);
-        Constant vmtarget = memberNameVmtargetField.readValue(memberName);
-
-        // Create a method from the vmtarget pointer
-        Class<?> c = (Class<?>) HotSpotObjectConstant.asObject(clazz);
-        HotSpotResolvedObjectType holderClass = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(c);
-        HotSpotResolvedJavaMethod targetMethod = HotSpotResolvedJavaMethod.fromMetaspace(vmtarget.asLong());
-
-        // In lambda forms we erase signature types to avoid resolving issues
-        // involving class loaders. When we optimize a method handle invoke
-        // to a direct call we must cast the receiver and arguments to its
-        // actual types.
-        HotSpotSignature signature = targetMethod.getSignature();
-        final boolean isStatic = targetMethod.isStatic();
-        final int receiverSkip = isStatic ? 0 : 1;
-
-        // Cast receiver to its type.
-        if (!isStatic) {
-            JavaType receiverType = holderClass;
-            maybeCastArgument(0, receiverType);
-        }
-
-        // Cast reference arguments to its type.
-        for (int index = 0; index < signature.getParameterCount(false); index++) {
-            JavaType parameterType = signature.getParameterType(index, holderClass);
-            maybeCastArgument(receiverSkip + index, parameterType);
-        }
-
-        // Try to get the most accurate receiver type
-        if (this instanceof MethodHandleLinkToVirtualNode || this instanceof MethodHandleLinkToInterfaceNode) {
-            ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver().stamp());
-            if (receiverType != null) {
-                ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
-                if (concreteMethod != null) {
-                    return createTargetInvokeNode(concreteMethod);
-                }
-            }
-        }
-
-        if (targetMethod.canBeStaticallyBound()) {
-            return createTargetInvokeNode(targetMethod);
-        }
-
-        ResolvedJavaMethod concreteMethod = targetMethod.uniqueConcreteMethod();
-        if (concreteMethod != null) {
-            return createTargetInvokeNode(concreteMethod);
-        }
-
-        return null;
-    }
-
-    /**
-     * Inserts a node to cast the argument at index to the given type if the given type is more
-     * concrete than the argument type.
-     *
-     * @param index of the argument to be cast
-     * @param type the type the argument should be cast to
-     */
-    private void maybeCastArgument(int index, JavaType type) {
-        if (type instanceof ResolvedJavaType) {
-            ResolvedJavaType targetType = (ResolvedJavaType) type;
-            if (!targetType.isPrimitive()) {
-                ValueNode argument = arguments.get(index);
-                ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
-                if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
-                    PiNode piNode = graph().unique(new PiNode(argument, StampFactory.declared(targetType)));
-                    arguments.set(index, piNode);
-                }
-            }
-        }
-    }
-
-    /**
-     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
-     * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}.
-     *
-     * @param targetMethod the method the be called
-     * @return invoke node for the member name target
-     */
-    private InvokeNode createTargetInvokeNode(ResolvedJavaMethod targetMethod) {
-        InvokeKind invokeKind = targetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
-        JavaType returnType = targetMethod.getSignature().getReturnType(null);
-
-        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
-        // needs to be popped.
-        ValueNode[] originalArguments = arguments.toArray(new ValueNode[arguments.size()]);
-        ValueNode[] targetArguments;
-        if (this instanceof MethodHandleInvokeBasicNode) {
-            targetArguments = originalArguments;
-        } else {
-            assert this instanceof MethodHandleLinkToStaticNode || this instanceof MethodHandleLinkToSpecialNode || this instanceof MethodHandleLinkToVirtualNode ||
-                            this instanceof MethodHandleLinkToInterfaceNode : this;
-            targetArguments = Arrays.copyOfRange(originalArguments, 0, arguments.size() - 1);
-        }
-
-        // If there is already replacement information, use that instead.
-        MethodCallTargetNode callTarget;
-        if (replacementTargetMethod == null) {
-            callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, getTargetMethod(), originalArguments, getReturnType());
-        } else {
-            ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]);
-            callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, replacementTargetMethod, args, replacementReturnType);
-        }
-        graph().add(callTarget);
-
-        // The call target can have a different return type than the invoker,
-        // e.g. the target returns an Object but the invoker void. In this case
-        // we need to use the stamp of the invoker. Note: always using the
-        // invoker's stamp would be wrong because it's a less concrete type
-        // (usually java.lang.Object).
-        InvokeNode invoke;
-        if (stamp() == StampFactory.forVoid()) {
-            invoke = new InvokeNode(callTarget, getBci(), stamp());
-        } else {
-            invoke = new InvokeNode(callTarget, getBci());
-        }
-        graph().add(invoke);
-        invoke.setStateAfter(stateAfter());
-        return invoke;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleInvokeBasicNode.java	Fri May 02 17:14:09 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013, 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.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .invokeBasic(Object...)}.
- */
-public class MethodHandleInvokeBasicNode extends AbstractMethodHandleNode {
-
-    public MethodHandleInvokeBasicNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        InvokeNode invoke = getInvokeBasicTarget();
-        if (invoke != null) {
-            return invoke;
-        }
-        return this;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToInterfaceNode.java	Fri May 02 17:14:09 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013, 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.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToInterface(Object...)}.
- */
-public class MethodHandleLinkToInterfaceNode extends AbstractMethodHandleNode {
-
-    public MethodHandleLinkToInterfaceNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        InvokeNode invoke = getLinkToTarget();
-        if (invoke != null) {
-            return invoke;
-        }
-        return this;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToSpecialNode.java	Fri May 02 17:14:09 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013, 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.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToSpecial(Object...)}.
- */
-public class MethodHandleLinkToSpecialNode extends AbstractMethodHandleNode {
-
-    public MethodHandleLinkToSpecialNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        InvokeNode invoke = getLinkToTarget();
-        if (invoke != null) {
-            return invoke;
-        }
-        return this;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToStaticNode.java	Fri May 02 17:14:09 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013, 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.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToStatic(Object...)}.
- */
-public class MethodHandleLinkToStaticNode extends AbstractMethodHandleNode {
-
-    public MethodHandleLinkToStaticNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        InvokeNode invoke = getLinkToTarget();
-        if (invoke != null) {
-            return invoke;
-        }
-        return this;
-    }
-
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToVirtualNode.java	Fri May 02 17:14:09 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013, 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.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToVirtual(Object...)}.
- */
-public class MethodHandleLinkToVirtualNode extends AbstractMethodHandleNode {
-
-    public MethodHandleLinkToVirtualNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        InvokeNode invoke = getLinkToTarget();
-        if (invoke != null) {
-            return invoke;
-        }
-        return this;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Fri May 02 11:04:51 2014 -0700
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2013, 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.hotspot.replacements;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import java.lang.invoke.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.api.replacements.MethodHandleAccessProvider.IntrinsicMethod;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.replacements.nodes.*;
+
+/**
+ * Node for invocation methods defined on the class {@link MethodHandle}.
+ */
+public class MethodHandleNode extends MacroNode implements Canonicalizable {
+
+    /** The method that this node is representing. */
+    private final IntrinsicMethod intrinsicMethod;
+
+    // Replacement method data
+    private ResolvedJavaMethod replacementTargetMethod;
+    private JavaType replacementReturnType;
+    @Input private final NodeInputList<ValueNode> replacementArguments;
+
+    public MethodHandleNode(Invoke invoke) {
+        super(invoke);
+
+        MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+        intrinsicMethod = lookupMethodHandleIntrinsic(callTarget.targetMethod());
+        assert intrinsicMethod != null;
+
+        // See if we need to save some replacement method data.
+        if (callTarget instanceof SelfReplacingMethodCallTargetNode) {
+            SelfReplacingMethodCallTargetNode selfReplacingMethodCallTargetNode = (SelfReplacingMethodCallTargetNode) callTarget;
+            replacementTargetMethod = selfReplacingMethodCallTargetNode.replacementTargetMethod();
+            replacementReturnType = selfReplacingMethodCallTargetNode.replacementReturnType();
+            replacementArguments = selfReplacingMethodCallTargetNode.replacementArguments();
+        } else {
+            // NodeInputList can't be null.
+            replacementArguments = new NodeInputList<>(this);
+        }
+    }
+
+    /**
+     * Returns the method handle method intrinsic identifier for the provided method, or
+     * {@code null} if the method is not a method that can be handled by this class.
+     */
+    public static IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) {
+        return methodHandleAccess().lookupMethodHandleIntrinsic(method);
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        InvokeNode invoke;
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                invoke = getInvokeBasicTarget();
+                break;
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                invoke = getLinkToTarget();
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+        if (invoke != null) {
+            return invoke;
+        }
+        return this;
+    }
+
+    /**
+     * Get the receiver of a MethodHandle.invokeBasic call.
+     *
+     * @return the receiver argument node
+     */
+    private ValueNode getReceiver() {
+        return arguments.first();
+    }
+
+    /**
+     * Get the MemberName argument of a MethodHandle.linkTo* call.
+     *
+     * @return the MemberName argument node (which is the last argument)
+     */
+    private ValueNode getMemberName() {
+        return arguments.last();
+    }
+
+    /**
+     * Returns the {@link MethodHandleAccessProvider} that provides introspection of internal
+     * {@link MethodHandle} data.
+     */
+    private static MethodHandleAccessProvider methodHandleAccess() {
+        return runtime().getHostProviders().getMethodHandleAccess();
+    }
+
+    /**
+     * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC }
+     * method) to get the target {@link InvokeNode} if the method handle receiver is constant.
+     *
+     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
+     */
+    protected InvokeNode getInvokeBasicTarget() {
+        ValueNode methodHandleNode = getReceiver();
+        if (methodHandleNode.isConstant()) {
+            return getTargetInvokeNode(methodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asConstant(), false));
+        }
+        return null;
+    }
+
+    /**
+     * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC},
+     * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and
+     * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if
+     * the member name argument is constant.
+     *
+     * @return invoke node for the member name target
+     */
+    protected InvokeNode getLinkToTarget() {
+        ValueNode memberNameNode = getMemberName();
+        if (memberNameNode.isConstant()) {
+            return getTargetInvokeNode(methodHandleAccess().resolveLinkToTarget(memberNameNode.asConstant()));
+        }
+        return null;
+    }
+
+    /**
+     * Helper function to get the {@link InvokeNode} for the targetMethod of a
+     * java.lang.invoke.MemberName.
+     *
+     * @param targetMethod the target, already loaded from the member name node
+     * @return invoke node for the member name target
+     */
+    private InvokeNode getTargetInvokeNode(ResolvedJavaMethod targetMethod) {
+        if (targetMethod == null) {
+            return null;
+        }
+
+        // In lambda forms we erase signature types to avoid resolving issues
+        // involving class loaders. When we optimize a method handle invoke
+        // to a direct call we must cast the receiver and arguments to its
+        // actual types.
+        Signature signature = targetMethod.getSignature();
+        final boolean isStatic = targetMethod.isStatic();
+        final int receiverSkip = isStatic ? 0 : 1;
+
+        // Cast receiver to its type.
+        if (!isStatic) {
+            JavaType receiverType = targetMethod.getDeclaringClass();
+            maybeCastArgument(0, receiverType);
+        }
+
+        // Cast reference arguments to its type.
+        for (int index = 0; index < signature.getParameterCount(false); index++) {
+            JavaType parameterType = signature.getParameterType(index, targetMethod.getDeclaringClass());
+            maybeCastArgument(receiverSkip + index, parameterType);
+        }
+
+        // Try to get the most accurate receiver type
+        if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
+            ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver().stamp());
+            if (receiverType != null) {
+                ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
+                if (concreteMethod != null) {
+                    return createTargetInvokeNode(concreteMethod);
+                }
+            }
+        }
+
+        if (targetMethod.canBeStaticallyBound()) {
+            return createTargetInvokeNode(targetMethod);
+        }
+
+        ResolvedJavaMethod concreteMethod = targetMethod.getDeclaringClass().findUniqueConcreteMethod(targetMethod);
+        if (concreteMethod != null) {
+            return createTargetInvokeNode(concreteMethod);
+        }
+
+        return null;
+    }
+
+    /**
+     * Inserts a node to cast the argument at index to the given type if the given type is more
+     * concrete than the argument type.
+     *
+     * @param index of the argument to be cast
+     * @param type the type the argument should be cast to
+     */
+    private void maybeCastArgument(int index, JavaType type) {
+        if (type instanceof ResolvedJavaType) {
+            ResolvedJavaType targetType = (ResolvedJavaType) type;
+            if (!targetType.isPrimitive()) {
+                ValueNode argument = arguments.get(index);
+                ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
+                if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
+                    PiNode piNode = graph().unique(new PiNode(argument, StampFactory.declared(targetType)));
+                    arguments.set(index, piNode);
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
+     * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}.
+     *
+     * @param targetMethod the method the be called
+     * @return invoke node for the member name target
+     */
+    private InvokeNode createTargetInvokeNode(ResolvedJavaMethod targetMethod) {
+        InvokeKind invokeKind = targetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+        JavaType returnType = targetMethod.getSignature().getReturnType(null);
+
+        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
+        // needs to be popped.
+        ValueNode[] originalArguments = arguments.toArray(new ValueNode[arguments.size()]);
+        ValueNode[] targetArguments;
+        switch (intrinsicMethod) {
+            case INVOKE_BASIC:
+                targetArguments = originalArguments;
+                break;
+            case LINK_TO_STATIC:
+            case LINK_TO_SPECIAL:
+            case LINK_TO_VIRTUAL:
+            case LINK_TO_INTERFACE:
+                targetArguments = Arrays.copyOfRange(originalArguments, 0, arguments.size() - 1);
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+
+        // If there is already replacement information, use that instead.
+        MethodCallTargetNode callTarget;
+        if (replacementTargetMethod == null) {
+            callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, getTargetMethod(), originalArguments, getReturnType());
+        } else {
+            ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]);
+            callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, replacementTargetMethod, args, replacementReturnType);
+        }
+        graph().add(callTarget);
+
+        // The call target can have a different return type than the invoker,
+        // e.g. the target returns an Object but the invoker void. In this case
+        // we need to use the stamp of the invoker. Note: always using the
+        // invoker's stamp would be wrong because it's a less concrete type
+        // (usually java.lang.Object).
+        InvokeNode invoke;
+        if (stamp() == StampFactory.forVoid()) {
+            invoke = new InvokeNode(callTarget, getBci(), stamp());
+        } else {
+            invoke = new InvokeNode(callTarget, getBci());
+        }
+        graph().add(invoke);
+        invoke.setStateAfter(stateAfter());
+        return invoke;
+    }
+
+}