21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import jdk.internal.misc.Unsafe;
29 import jdk.internal.vm.annotation.ForceInline;
30 import jdk.internal.vm.annotation.Stable;
31 import sun.invoke.util.ValueConversions;
32 import sun.invoke.util.VerifyAccess;
33 import sun.invoke.util.VerifyType;
34 import sun.invoke.util.Wrapper;
35
36 import java.lang.ref.WeakReference;
37 import java.util.Arrays;
38 import java.util.Objects;
39
40 import static java.lang.invoke.LambdaForm.*;
41 import static java.lang.invoke.MethodHandleNatives.Constants.*;
42 import static java.lang.invoke.MethodHandleStatics.UNSAFE;
43 import static java.lang.invoke.MethodHandleStatics.newInternalError;
44 import static java.lang.invoke.MethodTypeForm.*;
45
46 /**
47 * The flavor of method handle which implements a constant reference
48 * to a class member.
49 * @author jrose
50 */
51 class DirectMethodHandle extends MethodHandle {
52 final MemberName member;
53
54 // Constructors and factory methods in this class *must* be package scoped or private.
55 private DirectMethodHandle(MethodType mtype, LambdaForm form, MemberName member) {
56 super(mtype, form);
57 if (!member.isResolved()) throw new InternalError();
58
59 if (member.getDeclaringClass().isInterface() &&
60 member.isMethod() && !member.isAbstract()) {
172 which = LF_INVSTATIC_INIT;
173 }
174 LambdaForm lform = preparedLambdaForm(mtype, which);
175 maybeCompile(lform, m);
176 assert(lform.methodType().dropParameterTypes(0, 1)
177 .equals(m.getInvocationType().basicType()))
178 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
179 return lform;
180 }
181
182 private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
183 LambdaForm lform = mtype.form().cachedLambdaForm(which);
184 if (lform != null) return lform;
185 lform = makePreparedLambdaForm(mtype, which);
186 return mtype.form().setCachedLambdaForm(which, lform);
187 }
188
189 static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
190 boolean needsInit = (which == LF_INVSTATIC_INIT);
191 boolean doesAlloc = (which == LF_NEWINVSPECIAL);
192 String linkerName, lambdaName;
193 switch (which) {
194 case LF_INVVIRTUAL: linkerName = "linkToVirtual"; lambdaName = "DMH.invokeVirtual"; break;
195 case LF_INVSTATIC: linkerName = "linkToStatic"; lambdaName = "DMH.invokeStatic"; break;
196 case LF_INVSTATIC_INIT:linkerName = "linkToStatic"; lambdaName = "DMH.invokeStaticInit"; break;
197 case LF_INVSPECIAL: linkerName = "linkToSpecial"; lambdaName = "DMH.invokeSpecial"; break;
198 case LF_INVINTERFACE: linkerName = "linkToInterface"; lambdaName = "DMH.invokeInterface"; break;
199 case LF_NEWINVSPECIAL: linkerName = "linkToSpecial"; lambdaName = "DMH.newInvokeSpecial"; break;
200 default: throw new InternalError("which="+which);
201 }
202
203 MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
204 if (doesAlloc)
205 mtypeWithArg = mtypeWithArg
206 .insertParameterTypes(0, Object.class) // insert newly allocated obj
207 .changeReturnType(void.class); // <init> returns void
208 MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
209 try {
210 linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
211 } catch (ReflectiveOperationException ex) {
212 throw newInternalError(ex);
213 }
214 final int DMH_THIS = 0;
215 final int ARG_BASE = 1;
216 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
217 int nameCursor = ARG_LIMIT;
218 final int NEW_OBJ = (doesAlloc ? nameCursor++ : -1);
219 final int GET_MEMBER = nameCursor++;
223 if (doesAlloc) {
224 // names = { argx,y,z,... new C, init method }
225 names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
226 names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
227 } else if (needsInit) {
228 names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
229 } else {
230 names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
231 }
232 assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
233 Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
234 assert(outArgs[outArgs.length-1] == names[GET_MEMBER]); // look, shifted args!
235 int result = LAST_RESULT;
236 if (doesAlloc) {
237 assert(outArgs[outArgs.length-2] == names[NEW_OBJ]); // got to move this one
238 System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
239 outArgs[0] = names[NEW_OBJ];
240 result = NEW_OBJ;
241 }
242 names[LINKER_CALL] = new Name(linker, outArgs);
243 lambdaName += "_" + shortenSignature(basicTypeSignature(mtype));
244 LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result);
245
246 // This is a tricky bit of code. Don't send it through the LF interpreter.
247 lform.compileToBytecode(Holder.class);
248 return lform;
249 }
250
251 static Object findDirectMethodHandle(Name name) {
252 if (name.function == NF_internalMemberName ||
253 name.function == NF_internalMemberNameEnsureInit ||
254 name.function == NF_constructorMethod) {
255 assert(name.arguments.length == 1);
256 return name.arguments[0];
257 }
258 return null;
259 }
260
261 private static void maybeCompile(LambdaForm lform, MemberName m) {
262 if (lform.vmentry == null && VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
263 // Help along bootstrapping...
264 lform.compileToBytecode();
265 }
266
267 /** Static wrapper for DirectMethodHandle.internalMemberName. */
688 .getDeclaredMethod("checkBase", Object.class)),
689 NF_staticBase = new NamedFunction(DirectMethodHandle.class
690 .getDeclaredMethod("staticBase", Object.class)),
691 NF_staticOffset = new NamedFunction(DirectMethodHandle.class
692 .getDeclaredMethod("staticOffset", Object.class)),
693 NF_checkCast = new NamedFunction(DirectMethodHandle.class
694 .getDeclaredMethod("checkCast", Object.class, Object.class)),
695 NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
696 .getDeclaredMethod("allocateInstance", Object.class)),
697 NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
698 .getDeclaredMethod("constructorMethod", Object.class))
699 };
700 // Each nf must be statically invocable or we get tied up in our bootstraps.
701 assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
702 } catch (ReflectiveOperationException ex) {
703 throw newInternalError(ex);
704 }
705 }
706
707 static {
708 // The DMH class will contain pre-generated DirectMethodHandles resolved
709 // speculatively using MemberName.getFactory().resolveOrNull. However, that
710 // doesn't initialize the class, which subtly breaks inlining etc. By forcing
711 // initialization of the Holder class we avoid these issues.
712 UNSAFE.ensureClassInitialized(Holder.class);
713 }
714
715 /* Placeholder class for DirectMethodHandles generated ahead of time */
716 private final class Holder {}
717 }
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.invoke;
27
28 import jdk.internal.misc.Unsafe;
29 import jdk.internal.vm.annotation.ForceInline;
30 import jdk.internal.vm.annotation.Stable;
31 import sun.invoke.util.ValueConversions;
32 import sun.invoke.util.VerifyAccess;
33 import sun.invoke.util.VerifyType;
34 import sun.invoke.util.Wrapper;
35
36 import java.lang.ref.WeakReference;
37 import java.util.Arrays;
38 import java.util.Objects;
39
40 import static java.lang.invoke.LambdaForm.*;
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()) {
173 which = LF_INVSTATIC_INIT;
174 }
175 LambdaForm lform = preparedLambdaForm(mtype, which);
176 maybeCompile(lform, m);
177 assert(lform.methodType().dropParameterTypes(0, 1)
178 .equals(m.getInvocationType().basicType()))
179 : Arrays.asList(m, m.getInvocationType().basicType(), lform, lform.methodType());
180 return lform;
181 }
182
183 private static LambdaForm preparedLambdaForm(MethodType mtype, int which) {
184 LambdaForm lform = mtype.form().cachedLambdaForm(which);
185 if (lform != null) return lform;
186 lform = makePreparedLambdaForm(mtype, which);
187 return mtype.form().setCachedLambdaForm(which, lform);
188 }
189
190 static LambdaForm makePreparedLambdaForm(MethodType mtype, int which) {
191 boolean needsInit = (which == LF_INVSTATIC_INIT);
192 boolean doesAlloc = (which == LF_NEWINVSPECIAL);
193 String linkerName;
194 LambdaForm.Kind kind;
195 switch (which) {
196 case LF_INVVIRTUAL: linkerName = "linkToVirtual"; kind = DIRECT_INVOKE_VIRTUAL; break;
197 case LF_INVSTATIC: linkerName = "linkToStatic"; kind = DIRECT_INVOKE_STATIC; break;
198 case LF_INVSTATIC_INIT:linkerName = "linkToStatic"; kind = DIRECT_INVOKE_STATIC_INIT; break;
199 case LF_INVSPECIAL: linkerName = "linkToSpecial"; kind = DIRECT_INVOKE_SPECIAL; break;
200 case LF_INVINTERFACE: linkerName = "linkToInterface"; kind = DIRECT_INVOKE_INTERFACE; break;
201 case LF_NEWINVSPECIAL: linkerName = "linkToSpecial"; kind = DIRECT_NEW_INVOKE_SPECIAL; break;
202 default: throw new InternalError("which="+which);
203 }
204
205 MethodType mtypeWithArg = mtype.appendParameterTypes(MemberName.class);
206 if (doesAlloc)
207 mtypeWithArg = mtypeWithArg
208 .insertParameterTypes(0, Object.class) // insert newly allocated obj
209 .changeReturnType(void.class); // <init> returns void
210 MemberName linker = new MemberName(MethodHandle.class, linkerName, mtypeWithArg, REF_invokeStatic);
211 try {
212 linker = IMPL_NAMES.resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class);
213 } catch (ReflectiveOperationException ex) {
214 throw newInternalError(ex);
215 }
216 final int DMH_THIS = 0;
217 final int ARG_BASE = 1;
218 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount();
219 int nameCursor = ARG_LIMIT;
220 final int NEW_OBJ = (doesAlloc ? nameCursor++ : -1);
221 final int GET_MEMBER = nameCursor++;
225 if (doesAlloc) {
226 // names = { argx,y,z,... new C, init method }
227 names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
228 names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
229 } else if (needsInit) {
230 names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
231 } else {
232 names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
233 }
234 assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
235 Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
236 assert(outArgs[outArgs.length-1] == names[GET_MEMBER]); // look, shifted args!
237 int result = LAST_RESULT;
238 if (doesAlloc) {
239 assert(outArgs[outArgs.length-2] == names[NEW_OBJ]); // got to move this one
240 System.arraycopy(outArgs, 0, outArgs, 1, outArgs.length-2);
241 outArgs[0] = names[NEW_OBJ];
242 result = NEW_OBJ;
243 }
244 names[LINKER_CALL] = new Name(linker, outArgs);
245 String lambdaName = kind.defaultLambdaName + "_" + shortenSignature(basicTypeSignature(mtype));
246 LambdaForm lform = new LambdaForm(lambdaName, ARG_LIMIT, names, result, kind);
247
248 // This is a tricky bit of code. Don't send it through the LF interpreter.
249 lform.compileToBytecode();
250 return lform;
251 }
252
253 static Object findDirectMethodHandle(Name name) {
254 if (name.function == NF_internalMemberName ||
255 name.function == NF_internalMemberNameEnsureInit ||
256 name.function == NF_constructorMethod) {
257 assert(name.arguments.length == 1);
258 return name.arguments[0];
259 }
260 return null;
261 }
262
263 private static void maybeCompile(LambdaForm lform, MemberName m) {
264 if (lform.vmentry == null && VerifyAccess.isSamePackage(m.getDeclaringClass(), MethodHandle.class))
265 // Help along bootstrapping...
266 lform.compileToBytecode();
267 }
268
269 /** Static wrapper for DirectMethodHandle.internalMemberName. */
690 .getDeclaredMethod("checkBase", Object.class)),
691 NF_staticBase = new NamedFunction(DirectMethodHandle.class
692 .getDeclaredMethod("staticBase", Object.class)),
693 NF_staticOffset = new NamedFunction(DirectMethodHandle.class
694 .getDeclaredMethod("staticOffset", Object.class)),
695 NF_checkCast = new NamedFunction(DirectMethodHandle.class
696 .getDeclaredMethod("checkCast", Object.class, Object.class)),
697 NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
698 .getDeclaredMethod("allocateInstance", Object.class)),
699 NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
700 .getDeclaredMethod("constructorMethod", Object.class))
701 };
702 // Each nf must be statically invocable or we get tied up in our bootstraps.
703 assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
704 } catch (ReflectiveOperationException ex) {
705 throw newInternalError(ex);
706 }
707 }
708
709 static {
710 // The Holder class will contain pre-generated DirectMethodHandles resolved
711 // speculatively using MemberName.getFactory().resolveOrNull. However, that
712 // doesn't initialize the class, which subtly breaks inlining etc. By forcing
713 // initialization of the Holder class we avoid these issues.
714 UNSAFE.ensureClassInitialized(Holder.class);
715 }
716
717 /* Placeholder class for DirectMethodHandles generated ahead of time */
718 final class Holder {}
719 }
|