001/*
002 * Copyright (c) 2014, 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 jdk.internal.jvmci.hotspot;
024
025import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*;
026import static jdk.internal.jvmci.hotspot.HotSpotResolvedJavaType.*;
027import static jdk.internal.jvmci.hotspot.HotSpotResolvedObjectTypeImpl.*;
028import jdk.internal.jvmci.common.*;
029import jdk.internal.jvmci.meta.*;
030
031public class HotSpotMethodHandleAccessProvider implements MethodHandleAccessProvider, HotSpotProxified {
032
033    private final ConstantReflectionProvider constantReflection;
034
035    public HotSpotMethodHandleAccessProvider(ConstantReflectionProvider constantReflection) {
036        this.constantReflection = constantReflection;
037    }
038
039    /**
040     * Lazy initialization to break class initialization cycle. Field and method lookup is only
041     * possible after the {@link HotSpotJVMCIRuntime} is fully initialized.
042     */
043    static class LazyInitialization {
044        static final ResolvedJavaField methodHandleFormField;
045        static final ResolvedJavaField lambdaFormVmentryField;
046        static final ResolvedJavaMethod lambdaFormCompileToBytecodeMethod;
047        static final ResolvedJavaField memberNameVmtargetField;
048
049        /**
050         * Search for an instance field with the given name in a class.
051         *
052         * @param className name of the class to search in
053         * @param fieldName name of the field to be searched
054         * @return resolved java field
055         * @throws ClassNotFoundException
056         */
057        private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException {
058            Class<?> clazz = Class.forName(className);
059            ResolvedJavaType type = fromClass(clazz);
060            ResolvedJavaField[] fields = type.getInstanceFields(false);
061            for (ResolvedJavaField field : fields) {
062                if (field.getName().equals(fieldName)) {
063                    return field;
064                }
065            }
066            return null;
067        }
068
069        private static ResolvedJavaMethod findMethodInClass(String className, String methodName) throws ClassNotFoundException {
070            Class<?> clazz = Class.forName(className);
071            HotSpotResolvedObjectTypeImpl type = fromObjectClass(clazz);
072            ResolvedJavaMethod result = null;
073            for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
074                if (method.getName().equals(methodName)) {
075                    assert result == null : "more than one method found: " + className + "." + methodName;
076                    result = method;
077                }
078            }
079            assert result != null : "method not found: " + className + "." + methodName;
080            return result;
081        }
082
083        static {
084            try {
085                methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form");
086                lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry");
087                lambdaFormCompileToBytecodeMethod = findMethodInClass("java.lang.invoke.LambdaForm", "compileToBytecode");
088                memberNameVmtargetField = findFieldInClass("java.lang.invoke.MemberName", "vmtarget");
089            } catch (Throwable ex) {
090                throw new JVMCIError(ex);
091            }
092        }
093    }
094
095    @Override
096    public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) {
097        int intrinsicId = ((HotSpotResolvedJavaMethodImpl) method).intrinsicId();
098        if (intrinsicId != 0) {
099            return getMethodHandleIntrinsic(intrinsicId);
100        }
101        return null;
102    }
103
104    public static IntrinsicMethod getMethodHandleIntrinsic(int intrinsicId) {
105        HotSpotVMConfig config = runtime().getConfig();
106        if (intrinsicId == config.vmIntrinsicInvokeBasic) {
107            return IntrinsicMethod.INVOKE_BASIC;
108        } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
109            return IntrinsicMethod.LINK_TO_INTERFACE;
110        } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
111            return IntrinsicMethod.LINK_TO_SPECIAL;
112        } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
113            return IntrinsicMethod.LINK_TO_STATIC;
114        } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
115            return IntrinsicMethod.LINK_TO_VIRTUAL;
116        }
117        return null;
118    }
119
120    @Override
121    public ResolvedJavaMethod resolveInvokeBasicTarget(JavaConstant methodHandle, boolean forceBytecodeGeneration) {
122        if (methodHandle.isNull()) {
123            return null;
124        }
125
126        /* Load non-public field: LambdaForm MethodHandle.form */
127        JavaConstant lambdaForm = constantReflection.readFieldValue(LazyInitialization.methodHandleFormField, methodHandle);
128        if (lambdaForm.isNull()) {
129            return null;
130        }
131
132        JavaConstant memberName;
133        if (forceBytecodeGeneration) {
134            /* Invoke non-public method: MemberName LambdaForm.compileToBytecode() */
135            memberName = LazyInitialization.lambdaFormCompileToBytecodeMethod.invoke(lambdaForm, new JavaConstant[0]);
136        } else {
137            /* Load non-public field: MemberName LambdaForm.vmentry */
138            memberName = constantReflection.readFieldValue(LazyInitialization.lambdaFormVmentryField, lambdaForm);
139        }
140        return getTargetMethod(memberName);
141    }
142
143    @Override
144    public ResolvedJavaMethod resolveLinkToTarget(JavaConstant memberName) {
145        return getTargetMethod(memberName);
146    }
147
148    /**
149     * Returns the {@link ResolvedJavaMethod} for the vmtarget of a java.lang.invoke.MemberName.
150     */
151    private ResolvedJavaMethod getTargetMethod(JavaConstant memberName) {
152        if (memberName.isNull()) {
153            return null;
154        }
155
156        /* Load injected field: JVM_Method* MemberName.vmtarget */
157        JavaConstant vmtarget = constantReflection.readFieldValue(LazyInitialization.memberNameVmtargetField, memberName);
158        /* Create a method from the vmtarget method pointer. */
159        return HotSpotResolvedJavaMethodImpl.fromMetaspace(vmtarget.asLong());
160    }
161}