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;
|