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}