41 import static java.lang.invoke.LambdaForm.Kind.*; 42 import static java.lang.invoke.MethodHandleNatives.Constants.*; 43 import static java.lang.invoke.MethodHandleStatics.UNSAFE; 44 import static java.lang.invoke.MethodHandleStatics.newInternalError; 45 import static java.lang.invoke.MethodTypeForm.*; 46 47 /** 48 * The flavor of method handle which implements a constant reference 49 * to a class member. 50 * @author jrose 51 */ 52 class DirectMethodHandle extends MethodHandle { 53 final MemberName member; 54 55 // Constructors and factory methods in this class *must* be package scoped or private. 56 private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) { 57 super(mtype, form); 58 if (!member.isResolved()) throw new InternalError(); 59 60 if (member.getDeclaringClass().isInterface() && 61 member.isMethod() && !member.isAbstract()) { 62 // Check for corner case: invokeinterface of Object method 63 MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind()); 64 m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null); 65 if (m != null && m.isPublic()) { 66 assert(member.getReferenceKind() == m.getReferenceKind()); // else this.form is wrong 67 member = m; 68 } 69 } 70 71 this.member = member; 72 } 73 74 // Factory methods: 75 static DirectMethodHandle make(byte refKind, Class<?> refc, MemberName member, Class<?> callerClass) { 76 MethodType mtype = member.getMethodOrFieldType(); 77 if (!member.isStatic()) { 78 if (!member.getDeclaringClass().isAssignableFrom(refc) || member.isConstructor()) 79 throw new InternalError(member.toString()); 80 mtype = mtype.insertParameterTypes(0, refc); 81 } 82 if (!member.isField()) { 83 switch (refKind) { 84 case REF_invokeSpecial: { 85 member = member.asSpecial(); 86 LambdaForm lform = preparedLambdaForm(member, callerClass); 87 Class<?> checkClass = refc; // Class to use for receiver type check 88 if (callerClass != null) { 89 checkClass = callerClass; // potentially strengthen to caller class 90 } 91 return new Special(mtype, lform, member, checkClass); 92 } 93 case REF_invokeInterface: { 94 LambdaForm lform = preparedLambdaForm(member, callerClass); 95 return new Interface(mtype, lform, member, refc); 96 } 97 default: { 98 LambdaForm lform = preparedLambdaForm(member, callerClass); 99 return new DirectMethodHandle(mtype, lform, member); 100 } 101 } 102 } else { 103 LambdaForm lform = preparedFieldLambdaForm(member); 104 if (member.isStatic()) { 105 long offset = MethodHandleNatives.staticFieldOffset(member); 106 Object base = MethodHandleNatives.staticFieldBase(member); 107 return new StaticAccessor(mtype, lform, member, base, offset); 108 } else { 109 long offset = MethodHandleNatives.objectFieldOffset(member); 110 assert(offset == (int)offset); 111 return new Accessor(mtype, lform, member, (int)offset); 112 } 113 } 114 } 115 static DirectMethodHandle make(Class<?> refc, MemberName member) { 116 byte refKind = member.getReferenceKind(); 117 if (refKind == REF_invokeSpecial) 118 refKind = REF_invokeVirtual; 148 149 @Override 150 String internalProperties() { 151 return "\n& DMH.MN="+internalMemberName(); 152 } 153 154 //// Implementation methods. 155 @Override 156 @ForceInline 157 MemberName internalMemberName() { 158 return member; 159 } 160 161 private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(); 162 163 /** 164 * Create a LF which can invoke the given method. 165 * Cache and share this structure among all methods with 166 * the same basicType and refKind. 167 */ 168 private static LambdaForm preparedLambdaForm(MemberName m, Class<?> callerClass) { 169 assert(m.isInvocable()) : m; // call preparedFieldLambdaForm instead 170 MethodType mtype = m.getInvocationType().basicType(); 171 assert(!m.isMethodHandleInvoke()) : m; 172 int which; 173 switch (m.getReferenceKind()) { 174 case REF_invokeVirtual: which = LF_INVVIRTUAL; break; 175 case REF_invokeStatic: which = LF_INVSTATIC; break; 176 case REF_invokeSpecial: which = LF_INVSPECIAL; break; 177 case REF_invokeInterface: which = LF_INVINTERFACE; break; 178 case REF_newInvokeSpecial: which = LF_NEWINVSPECIAL; break; 179 default: throw new InternalError(m.toString()); 180 } 181 if (which == LF_INVSTATIC && shouldBeInitialized(m)) { 182 // precompute the barrier-free version: 183 preparedLambdaForm(mtype, which); 184 which = LF_INVSTATIC_INIT; 185 } 186 if (which == LF_INVSPECIAL && callerClass != null && callerClass.isInterface()) { 187 which = LF_INVSPECIAL_IFC; 188 } 189 LambdaForm lform = preparedLambdaForm(mtype, which); 190 maybeCompile(lform, m); 191 assert(lform.methodType().dropParameterTypes(0, 1) 192 .equals(m.getInvocationType().basicType())) 193 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType()); 194 return lform; 195 } 196 197 private static LambdaForm preparedLambdaForm(MemberName m) { 198 return preparedLambdaForm(m, null); 199 } 200 201 private static LambdaForm preparedLambdaForm(MethodType mtype, int which) { 202 LambdaForm lform = mtype.form().cachedLambdaForm(which); 203 if (lform != null) return lform; 204 lform = makePreparedLambdaForm(mtype, which); 205 return mtype.form().setCachedLambdaForm(which, lform); 206 } 207 208 static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) { 209 boolean needsInit = (which == LF_INVSTATIC_INIT); 210 boolean doesAlloc = (which == LF_NEWINVSPECIAL); 211 boolean needsReceiverCheck = (which == LF_INVINTERFACE || 212 which == LF_INVSPECIAL_IFC); 213 214 String linkerName; 215 LambdaForm.Kind kind; 216 switch (which) { 217 case LF_INVVIRTUAL: linkerName = "linkToVirtual"; kind = DIRECT_INVOKE_VIRTUAL; break; 218 case LF_INVSTATIC: linkerName = "linkToStatic"; kind = DIRECT_INVOKE_STATIC; break; | 41 import static java.lang.invoke.LambdaForm.Kind.*; 42 import static java.lang.invoke.MethodHandleNatives.Constants.*; 43 import static java.lang.invoke.MethodHandleStatics.UNSAFE; 44 import static java.lang.invoke.MethodHandleStatics.newInternalError; 45 import static java.lang.invoke.MethodTypeForm.*; 46 47 /** 48 * The flavor of method handle which implements a constant reference 49 * to a class member. 50 * @author jrose 51 */ 52 class DirectMethodHandle extends MethodHandle { 53 final MemberName member; 54 55 // Constructors and factory methods in this class *must* be package scoped or private. 56 private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) { 57 super(mtype, form); 58 if (!member.isResolved()) throw new InternalError(); 59 60 if (member.getDeclaringClass().isInterface() && 61 member.getReferenceKind() == REF_invokeInterface && 62 member.isMethod() && !member.isAbstract()) { 63 // Check for corner case: invokeinterface of Object method 64 MemberName m = new MemberName(Object.class, member.getName(), member.getMethodType(), member.getReferenceKind()); 65 m = MemberName.getFactory().resolveOrNull(m.getReferenceKind(), m, null); 66 if (m != null && m.isPublic()) { 67 assert(member.getReferenceKind() == m.getReferenceKind()); // else this.form is wrong 68 member = m; 69 } 70 } 71 72 this.member = member; 73 } 74 75 // Factory methods: 76 static DirectMethodHandle make(byte refKind, Class<?> refc, MemberName member, Class<?> callerClass) { 77 MethodType mtype = member.getMethodOrFieldType(); 78 if (!member.isStatic()) { 79 if (!member.getDeclaringClass().isAssignableFrom(refc) || member.isConstructor()) 80 throw new InternalError(member.toString()); 81 mtype = mtype.insertParameterTypes(0, refc); 82 } 83 if (!member.isField()) { 84 // refKind reflects the original type of lookup via findSpecial or 85 // findVirtual etc. 86 switch (refKind) { 87 case REF_invokeSpecial: { 88 member = member.asSpecial(); 89 // if caller is an interface we need to adapt to get the 90 // receiver check inserted 91 if (callerClass == null) { 92 throw new InternalError("callerClass must not be null for REF_invokeSpecial"); 93 } 94 LambdaForm lform = preparedLambdaForm(member, callerClass.isInterface()); 95 return new Special(mtype, lform, member, callerClass); 96 } 97 case REF_invokeInterface: { 98 // for interfaces we always need the receiver typecheck, 99 // so we always pass 'true' to ensure we adapt if needed 100 // to include the REF_invokeSpecial case 101 LambdaForm lform = preparedLambdaForm(member, true); 102 return new Interface(mtype, lform, member, refc); 103 } 104 default: { 105 LambdaForm lform = preparedLambdaForm(member); 106 return new DirectMethodHandle(mtype, lform, member); 107 } 108 } 109 } else { 110 LambdaForm lform = preparedFieldLambdaForm(member); 111 if (member.isStatic()) { 112 long offset = MethodHandleNatives.staticFieldOffset(member); 113 Object base = MethodHandleNatives.staticFieldBase(member); 114 return new StaticAccessor(mtype, lform, member, base, offset); 115 } else { 116 long offset = MethodHandleNatives.objectFieldOffset(member); 117 assert(offset == (int)offset); 118 return new Accessor(mtype, lform, member, (int)offset); 119 } 120 } 121 } 122 static DirectMethodHandle make(Class<?> refc, MemberName member) { 123 byte refKind = member.getReferenceKind(); 124 if (refKind == REF_invokeSpecial) 125 refKind = REF_invokeVirtual; 155 156 @Override 157 String internalProperties() { 158 return "\n& DMH.MN="+internalMemberName(); 159 } 160 161 //// Implementation methods. 162 @Override 163 @ForceInline 164 MemberName internalMemberName() { 165 return member; 166 } 167 168 private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(); 169 170 /** 171 * Create a LF which can invoke the given method. 172 * Cache and share this structure among all methods with 173 * the same basicType and refKind. 174 */ 175 private static LambdaForm preparedLambdaForm(MemberName m, boolean adaptToSpecialIfc) { 176 assert(m.isInvocable()) : m; // call preparedFieldLambdaForm instead 177 MethodType mtype = m.getInvocationType().basicType(); 178 assert(!m.isMethodHandleInvoke()) : m; 179 int which; 180 // MemberName.getReferenceKind represents the JVM optimized form of the call 181 // as distinct from the "kind" passed to DMH.make which represents the original 182 // bytecode-equivalent request. Specifically private/final methods that use a direct 183 // call have getReferenceKind adapted to REF_invokeSpecial, even though the actual 184 // invocation mode may be invokevirtual or invokeinterface. 185 switch (m.getReferenceKind()) { 186 case REF_invokeVirtual: which = LF_INVVIRTUAL; break; 187 case REF_invokeStatic: which = LF_INVSTATIC; break; 188 case REF_invokeSpecial: which = LF_INVSPECIAL; break; 189 case REF_invokeInterface: which = LF_INVINTERFACE; break; 190 case REF_newInvokeSpecial: which = LF_NEWINVSPECIAL; break; 191 default: throw new InternalError(m.toString()); 192 } 193 if (which == LF_INVSTATIC && shouldBeInitialized(m)) { 194 // precompute the barrier-free version: 195 preparedLambdaForm(mtype, which); 196 which = LF_INVSTATIC_INIT; 197 } 198 if (which == LF_INVSPECIAL && adaptToSpecialIfc) { 199 which = LF_INVSPECIAL_IFC; 200 } 201 LambdaForm lform = preparedLambdaForm(mtype, which); 202 maybeCompile(lform, m); 203 assert(lform.methodType().dropParameterTypes(0, 1) 204 .equals(m.getInvocationType().basicType())) 205 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType()); 206 return lform; 207 } 208 209 private static LambdaForm preparedLambdaForm(MemberName m) { 210 return preparedLambdaForm(m, false); 211 } 212 213 private static LambdaForm preparedLambdaForm(MethodType mtype, int which) { 214 LambdaForm lform = mtype.form().cachedLambdaForm(which); 215 if (lform != null) return lform; 216 lform = makePreparedLambdaForm(mtype, which); 217 return mtype.form().setCachedLambdaForm(which, lform); 218 } 219 220 static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) { 221 boolean needsInit = (which == LF_INVSTATIC_INIT); 222 boolean doesAlloc = (which == LF_NEWINVSPECIAL); 223 boolean needsReceiverCheck = (which == LF_INVINTERFACE || 224 which == LF_INVSPECIAL_IFC); 225 226 String linkerName; 227 LambdaForm.Kind kind; 228 switch (which) { 229 case LF_INVVIRTUAL: linkerName = "linkToVirtual"; kind = DIRECT_INVOKE_VIRTUAL; break; 230 case LF_INVSTATIC: linkerName = "linkToStatic"; kind = DIRECT_INVOKE_STATIC; break; |