9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
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.org.objectweb.asm.ClassWriter;
29 import jdk.internal.org.objectweb.asm.Label;
30 import jdk.internal.org.objectweb.asm.MethodVisitor;
31 import jdk.internal.org.objectweb.asm.Opcodes;
32 import jdk.internal.org.objectweb.asm.Type;
33 import sun.invoke.util.VerifyAccess;
34 import sun.invoke.util.VerifyType;
35 import sun.invoke.util.Wrapper;
36 import sun.reflect.misc.ReflectUtil;
37
38 import java.io.File;
39 import java.io.FileOutputStream;
40 import java.io.IOException;
41 import java.lang.reflect.Modifier;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.HashMap;
45 import java.util.stream.Stream;
46
47 import static java.lang.invoke.LambdaForm.BasicType;
48 import static java.lang.invoke.LambdaForm.BasicType.*;
49 import static java.lang.invoke.LambdaForm.*;
50 import static java.lang.invoke.MethodHandleNatives.Constants.*;
51 import static java.lang.invoke.MethodHandleStatics.*;
52
53 /**
54 * Code generation backend for LambdaForm.
55 * <p>
56 * @author John Rose, JSR 292 EG
57 */
58 class InvokerBytecodeGenerator {
59 /** Define class names for convenience. */
60 private static final String MH = "java/lang/invoke/MethodHandle";
61 private static final String MHI = "java/lang/invoke/MethodHandleImpl";
62 private static final String LF = "java/lang/invoke/LambdaForm";
63 private static final String LFN = "java/lang/invoke/LambdaForm$Name";
64 private static final String CLS = "java/lang/Class";
65 private static final String OBJ = "java/lang/Object";
66 private static final String OBJARY = "[Ljava/lang/Object;";
67
68 private static final String LOOP_CLAUSES = MHI + "$LoopClauses";
69 private static final String MHARY2 = "[[L" + MH + ";";
70
71 private static final String LF_SIG = "L" + LF + ";";
72 private static final String LFN_SIG = "L" + LFN + ";";
73 private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";";
74 private static final String LLV_SIG = "(L" + OBJ + ";L" + OBJ + ";)V";
75 private static final String CLASS_PREFIX = LF + "$";
76 private static final String SOURCE_PREFIX = "LambdaForm$";
77
78 /** Name of its super class*/
79 static final String INVOKER_SUPER_NAME = OBJ;
80
81 /** Name of new class */
82 private final String className;
83
84 private final LambdaForm lambdaForm;
85 private final String invokerName;
86 private final MethodType invokerType;
87
88 /** Info about local variables in compiled lambda form */
89 private int[] localsMap; // index
90 private Class<?>[] localClasses; // type
91
92 /** ASM bytecode generation. */
93 private ClassWriter cw;
94 private MethodVisitor mv;
95
96 /** Single element internal class name lookup cache. */
97 private Class<?> lastClass;
98 private String lastInternalName;
99
100 private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
101 private static final Class<?> HOST_CLASS = LambdaForm.class;
102
103 /** Main constructor; other constructors delegate to this one. */
104 private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
105 String className, String invokerName, MethodType invokerType) {
106 int p = invokerName.indexOf('.');
107 if (p > -1) {
108 className = invokerName.substring(0, p);
109 invokerName = invokerName.substring(p + 1);
110 }
111 if (DUMP_CLASS_FILES) {
112 className = makeDumpableClassName(className);
113 }
114 this.className = className;
115 this.lambdaForm = lambdaForm;
116 this.invokerName = invokerName;
117 this.invokerType = invokerType;
118 this.localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots
119 this.localClasses = new Class<?>[localsMapSize+1];
120 }
121
204 }
205 }
206 });
207 }
208 }
209
210 private static String makeDumpableClassName(String className) {
211 Integer ctr;
212 synchronized (DUMP_CLASS_FILES_COUNTERS) {
213 ctr = DUMP_CLASS_FILES_COUNTERS.get(className);
214 if (ctr == null) ctr = 0;
215 DUMP_CLASS_FILES_COUNTERS.put(className, ctr+1);
216 }
217 String sfx = ctr.toString();
218 while (sfx.length() < 3)
219 sfx = "0"+sfx;
220 className += sfx;
221 return className;
222 }
223
224 class CpPatch {
225 final int index;
226 final Object value;
227 CpPatch(int index, Object value) {
228 this.index = index;
229 this.value = value;
230 }
231 public String toString() {
232 return "CpPatch/index="+index+",value="+value;
233 }
234 }
235
236 private final ArrayList<CpPatch> cpPatches = new ArrayList<>();
237
238 private int cph = 0; // for counting constant placeholders
239
240 String constantPlaceholder(Object arg) {
241 String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + cph++;
242 if (DUMP_CLASS_FILES) cpPlaceholder += " <<" + debugString(arg) + ">>";
243 // TODO check if arg is already in the constant pool
244 // insert placeholder in CP and remember the patch
245 int index = cw.newConst((Object) cpPlaceholder);
246 cpPatches.add(new CpPatch(index, arg));
247 return cpPlaceholder;
248 }
249
250 Object[] cpPatches(byte[] classFile) {
251 int size = getConstantPoolSize(classFile);
252 Object[] res = new Object[size];
253 for (CpPatch p : cpPatches) {
254 if (p.index >= size)
255 throw new InternalError("in cpool["+size+"]: "+p+"\n"+Arrays.toString(Arrays.copyOf(classFile, 20)));
256 res[p.index] = p.value;
257 }
258 return res;
259 }
260
261 private static String debugString(Object arg) {
262 if (arg instanceof MethodHandle) {
263 MethodHandle mh = (MethodHandle) arg;
264 MemberName member = mh.internalMemberName();
265 if (member != null)
266 return member.toString();
267 return mh.debugString();
268 }
269 return arg.toString();
270 }
271
272 /**
273 * Extract the number of constant pool entries from a given class file.
274 *
275 * @param classFile the bytes of the class file in question.
276 * @return the number of entries in the constant pool.
277 */
278 private static int getConstantPoolSize(byte[] classFile) {
279 // The first few bytes:
280 // u4 magic;
281 // u2 minor_version;
282 // u2 major_version;
283 // u2 constant_pool_count;
284 return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
285 }
286
287 /**
288 * Extract the MemberName of a newly-defined method.
289 */
290 private MemberName loadMethod(byte[] classFile) {
291 Class<?> invokerClass = loadAndInitializeInvokerClass(classFile, cpPatches(classFile));
292 return resolveInvokerMember(invokerClass, invokerName, invokerType);
293 }
294
295 /**
296 * Define a given class as anonymous class in the runtime system.
297 */
298 private static Class<?> loadAndInitializeInvokerClass(byte[] classBytes, Object[] patches) {
299 Class<?> invokerClass = UNSAFE.defineAnonymousClass(HOST_CLASS, classBytes, patches);
300 UNSAFE.ensureClassInitialized(invokerClass); // Make sure the class is initialized; VM might complain.
301 return invokerClass;
302 }
303
304 private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
305 MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
306 try {
307 member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class);
308 } catch (ReflectiveOperationException e) {
309 throw newInternalError(e);
310 }
311 return member;
312 }
313
314 /**
315 * Set up class file generation.
316 */
317 private ClassWriter classFilePrologue() {
318 final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC
319 cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
320 cw.visit(Opcodes.V1_8, NOT_ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
321 CLASS_PREFIX + className, null, INVOKER_SUPER_NAME, null);
322 cw.visitSource(SOURCE_PREFIX + className, null);
323 return cw;
324 }
325
326 private void methodPrologue() {
327 String invokerDesc = invokerType.toMethodDescriptorString();
328 mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
329 }
330
331 /**
332 * Tear down class file generation.
333 */
334 private void methodEpilogue() {
335 mv.visitMaxs(0, 0);
336 mv.visitEnd();
337 }
338
339 /*
340 * Low-level emit helpers.
341 */
342 private void emitConst(Object con) {
343 if (con == null) {
344 mv.visitInsn(Opcodes.ACONST_NULL);
345 return;
346 }
347 if (con instanceof Integer) {
348 emitIconstInsn((int) con);
349 return;
350 }
351 if (con instanceof Byte) {
352 emitIconstInsn((byte)con);
353 return;
354 }
355 if (con instanceof Short) {
356 emitIconstInsn((short)con);
357 return;
358 }
391 short sx = (short)x;
392 if (x == sx) {
393 if (sx >= 0 && sx <= 1) {
394 mv.visitInsn(Opcodes.DCONST_0 + (int) sx);
395 } else {
396 emitIconstInsn((int) x);
397 mv.visitInsn(Opcodes.I2D);
398 }
399 return;
400 }
401 }
402 if (con instanceof Boolean) {
403 emitIconstInsn((boolean) con ? 1 : 0);
404 return;
405 }
406 // fall through:
407 mv.visitLdcInsn(con);
408 }
409
410 private void emitIconstInsn(final int cst) {
411 if (cst >= -1 && cst <= 5) {
412 mv.visitInsn(Opcodes.ICONST_0 + cst);
413 } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
414 mv.visitIntInsn(Opcodes.BIPUSH, cst);
415 } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
416 mv.visitIntInsn(Opcodes.SIPUSH, cst);
417 } else {
418 mv.visitLdcInsn(cst);
419 }
420 }
421
422 /*
423 * NOTE: These load/store methods use the localsMap to find the correct index!
424 */
425 private void emitLoadInsn(BasicType type, int index) {
426 int opcode = loadInsnOpcode(type);
427 mv.visitVarInsn(opcode, localsMap[index]);
428 }
429
430 private int loadInsnOpcode(BasicType type) throws InternalError {
560 }
561 return false;
562 }
563
564 private void emitReferenceCast(Class<?> cls, Object arg) {
565 Name writeBack = null; // local to write back result
566 if (arg instanceof Name) {
567 Name n = (Name) arg;
568 if (lambdaForm.useCount(n) > 1) {
569 // This guy gets used more than once.
570 writeBack = n;
571 if (assertStaticType(cls, n)) {
572 return; // this cast was already performed
573 }
574 }
575 }
576 if (isStaticallyNameable(cls)) {
577 String sig = getInternalName(cls);
578 mv.visitTypeInsn(Opcodes.CHECKCAST, sig);
579 } else {
580 mv.visitLdcInsn(constantPlaceholder(cls));
581 mv.visitTypeInsn(Opcodes.CHECKCAST, CLS);
582 mv.visitInsn(Opcodes.SWAP);
583 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CLS, "cast", LL_SIG, false);
584 if (Object[].class.isAssignableFrom(cls))
585 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
586 else if (PROFILE_LEVEL > 0)
587 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ);
588 }
589 if (writeBack != null) {
590 mv.visitInsn(Opcodes.DUP);
591 emitAstoreInsn(writeBack.index());
592 }
593 }
594
595 /**
596 * Emits an actual return instruction conforming to the given return type.
597 */
598 private void emitReturnInsn(BasicType type) {
599 int opcode;
600 switch (type) {
601 case I_TYPE: opcode = Opcodes.IRETURN; break;
720 try {
721 Class<?> c = Class.forName(tp.getClassName(), false, null);
722 return true;
723 } catch (ClassNotFoundException e) {
724 return false;
725 }
726 }
727
728 static final String DONTINLINE_SIG = className("Ljdk/internal/vm/annotation/DontInline;");
729 static final String FORCEINLINE_SIG = className("Ljdk/internal/vm/annotation/ForceInline;");
730 static final String HIDDEN_SIG = className("Ljdk/internal/vm/annotation/Hidden;");
731 static final String INJECTEDPROFILE_SIG = className("Ljava/lang/invoke/InjectedProfile;");
732 static final String LF_COMPILED_SIG = className("Ljava/lang/invoke/LambdaForm$Compiled;");
733
734 /**
735 * Generate an invoker method for the passed {@link LambdaForm}.
736 */
737 private byte[] generateCustomizedCodeBytes() {
738 classFilePrologue();
739 addMethod();
740 bogusMethod(lambdaForm);
741
742 final byte[] classFile = toByteArray();
743 maybeDump(classFile);
744 return classFile;
745 }
746
747 void setClassWriter(ClassWriter cw) {
748 this.cw = cw;
749 }
750
751 void addMethod() {
752 methodPrologue();
753
754 // Suppress this method in backtraces displayed to the user.
755 mv.visitAnnotation(HIDDEN_SIG, true);
756
757 // Mark this method as a compiled LambdaForm
758 mv.visitAnnotation(LF_COMPILED_SIG, true);
759
760 if (lambdaForm.forceInline) {
761 // Force inlining of this invoker method.
762 mv.visitAnnotation(FORCEINLINE_SIG, true);
763 } else {
764 mv.visitAnnotation(DONTINLINE_SIG, true);
765 }
766
767 constantPlaceholder(lambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled.
768
769 if (lambdaForm.customized != null) {
770 // Since LambdaForm is customized for a particular MethodHandle, it's safe to substitute
771 // receiver MethodHandle (at slot #0) with an embedded constant and use it instead.
772 // It enables more efficient code generation in some situations, since embedded constants
773 // are compile-time constants for JIT compiler.
774 mv.visitLdcInsn(constantPlaceholder(lambdaForm.customized));
775 mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
776 assert(checkActualReceiver()); // expects MethodHandle on top of the stack
777 mv.visitVarInsn(Opcodes.ASTORE, localsMap[0]);
778 }
779
780 // iterate over the form's names, generating bytecode instructions for each
781 // start iterating at the first name following the arguments
782 Name onStack = null;
783 for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
784 Name name = lambdaForm.names[i];
785
786 emitStoreResult(onStack);
787 onStack = name; // unless otherwise modified below
788 MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
789 switch (intr) {
790 case SELECT_ALTERNATIVE:
791 assert lambdaForm.isSelectAlternative(i);
792 if (PROFILE_GWT) {
793 assert(name.arguments[0] instanceof Name &&
794 ((Name)name.arguments[0]).refersTo(MethodHandleImpl.class, "profileBoolean"));
884 assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE || arrayOpcode == Opcodes.ARRAYLENGTH;
885 Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
886 assert elementType != null;
887 emitPushArguments(name, 0);
888 if (arrayOpcode != Opcodes.ARRAYLENGTH && elementType.isPrimitive()) {
889 Wrapper w = Wrapper.forPrimitiveType(elementType);
890 arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
891 }
892 mv.visitInsn(arrayOpcode);
893 }
894
895 /**
896 * Emit an invoke for the given name.
897 */
898 void emitInvoke(Name name) {
899 assert(!name.isLinkerMethodInvoke()); // should use the static path for these
900 if (true) {
901 // push receiver
902 MethodHandle target = name.function.resolvedHandle();
903 assert(target != null) : name.exprString();
904 mv.visitLdcInsn(constantPlaceholder(target));
905 emitReferenceCast(MethodHandle.class, target);
906 } else {
907 // load receiver
908 emitAloadInsn(0);
909 emitReferenceCast(MethodHandle.class, null);
910 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
911 mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
912 // TODO more to come
913 }
914
915 // push arguments
916 emitPushArguments(name, 0);
917
918 // invocation
919 MethodType type = name.function.methodType();
920 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
921 }
922
923 private static Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
924 // Sample classes from each package we are willing to bind to statically:
940 static boolean isStaticallyInvocable(Name name) {
941 return isStaticallyInvocable(name.function.member());
942 }
943
944 static boolean isStaticallyInvocable(MemberName member) {
945 if (member == null) return false;
946 if (member.isConstructor()) return false;
947 Class<?> cls = member.getDeclaringClass();
948 // Fast-path non-private members declared by MethodHandles, which is a common
949 // case
950 if (MethodHandle.class.isAssignableFrom(cls) && !member.isPrivate()) {
951 assert(isStaticallyInvocableType(member.getMethodOrFieldType()));
952 return true;
953 }
954 if (cls.isArray() || cls.isPrimitive())
955 return false; // FIXME
956 if (cls.isAnonymousClass() || cls.isLocalClass())
957 return false; // inner class of some sort
958 if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
959 return false; // not on BCP
960 if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
961 return false;
962 if (!isStaticallyInvocableType(member.getMethodOrFieldType()))
963 return false;
964 if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
965 return true; // in java.lang.invoke package
966 if (member.isPublic() && isStaticallyNameable(cls))
967 return true;
968 return false;
969 }
970
971 private static boolean isStaticallyInvocableType(MethodType mtype) {
972 if (!isStaticallyNameable(mtype.returnType()))
973 return false;
974 for (Class<?> ptype : mtype.parameterArray())
975 if (!isStaticallyNameable(ptype))
976 return false;
977 return true;
978 }
979
980 static boolean isStaticallyNameable(Class<?> cls) {
981 if (cls == Object.class)
982 return true;
983 if (MethodHandle.class.isAssignableFrom(cls)) {
984 assert(!ReflectUtil.isVMAnonymousClass(cls));
985 return true;
986 }
987 while (cls.isArray())
988 cls = cls.getComponentType();
989 if (cls.isPrimitive())
990 return true; // int[].class, for example
991 if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: switch to supported API once it is added
992 return false;
993 // could use VerifyAccess.isClassAccessible but the following is a safe approximation
994 if (cls.getClassLoader() != Object.class.getClassLoader())
995 return false;
996 if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
997 return true;
998 if (!Modifier.isPublic(cls.getModifiers()))
999 return false;
1000 for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
1001 if (VerifyAccess.isSamePackage(pkgcls, cls))
1002 return true;
1003 }
1004 return false;
1005 }
1006
1007 void emitStaticInvoke(Name name) {
1008 emitStaticInvoke(name.function.member(), name);
1009 }
1010
1011 /**
1043 Class<?> rtype = member.getInvocationType().returnType();
1044 assert(!rtype.isPrimitive());
1045 if (rtype != Object.class && !rtype.isInterface()) {
1046 assertStaticType(rtype, name);
1047 }
1048 }
1049 }
1050
1051 void emitNewArray(Name name) throws InternalError {
1052 Class<?> rtype = name.function.methodType().returnType();
1053 if (name.arguments.length == 0) {
1054 // The array will be a constant.
1055 Object emptyArray;
1056 try {
1057 emptyArray = name.function.resolvedHandle().invoke();
1058 } catch (Throwable ex) {
1059 throw uncaughtException(ex);
1060 }
1061 assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
1062 assert(emptyArray.getClass() == rtype); // exact typing
1063 mv.visitLdcInsn(constantPlaceholder(emptyArray));
1064 emitReferenceCast(rtype, emptyArray);
1065 return;
1066 }
1067 Class<?> arrayElementType = rtype.getComponentType();
1068 assert(arrayElementType != null);
1069 emitIconstInsn(name.arguments.length);
1070 int xas = Opcodes.AASTORE;
1071 if (!arrayElementType.isPrimitive()) {
1072 mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
1073 } else {
1074 byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
1075 xas = arrayInsnOpcode(tc, xas);
1076 mv.visitIntInsn(Opcodes.NEWARRAY, tc);
1077 }
1078 // store arguments
1079 for (int i = 0; i < name.arguments.length; i++) {
1080 mv.visitInsn(Opcodes.DUP);
1081 emitIconstInsn(i);
1082 emitPushArgument(name, i);
1083 mv.visitInsn(xas);
1606 }
1607
1608 private void emitPushArgument(Name name, int paramIndex) {
1609 Object arg = name.arguments[paramIndex];
1610 Class<?> ptype = name.function.methodType().parameterType(paramIndex);
1611 emitPushArgument(ptype, arg);
1612 }
1613
1614 private void emitPushArgument(Class<?> ptype, Object arg) {
1615 BasicType bptype = basicType(ptype);
1616 if (arg instanceof Name) {
1617 Name n = (Name) arg;
1618 emitLoadInsn(n.type, n.index());
1619 emitImplicitConversion(n.type, ptype, n);
1620 } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
1621 emitConst(arg);
1622 } else {
1623 if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
1624 emitConst(arg);
1625 } else {
1626 mv.visitLdcInsn(constantPlaceholder(arg));
1627 emitImplicitConversion(L_TYPE, ptype, arg);
1628 }
1629 }
1630 }
1631
1632 /**
1633 * Store the name to its local, if necessary.
1634 */
1635 private void emitStoreResult(Name name) {
1636 if (name != null && name.type != V_TYPE) {
1637 // non-void: actually assign
1638 emitStoreInsn(name.type, name.index());
1639 }
1640 }
1641
1642 /**
1643 * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
1644 */
1645 private void emitReturn(Name onStack) {
1646 // return statement
1798 emitBoxing(Wrapper.forPrimitiveType(ptype));
1799 }
1800 mv.visitInsn(Opcodes.AASTORE);
1801 }
1802 // invoke
1803 emitAloadInsn(0);
1804 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
1805 mv.visitInsn(Opcodes.SWAP); // swap form and array; avoid local variable
1806 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
1807
1808 // maybe unbox
1809 Class<?> rtype = invokerType.returnType();
1810 if (rtype.isPrimitive() && rtype != void.class) {
1811 emitUnboxing(Wrapper.forPrimitiveType(rtype));
1812 }
1813
1814 // return statement
1815 emitReturnInsn(basicType(rtype));
1816
1817 methodEpilogue();
1818 bogusMethod(invokerType);
1819
1820 final byte[] classFile = cw.toByteArray();
1821 maybeDump(classFile);
1822 return classFile;
1823 }
1824
1825 /**
1826 * Generate bytecode for a NamedFunction invoker.
1827 */
1828 static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
1829 MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
1830 String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
1831 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
1832 return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
1833 }
1834
1835 private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
1836 MethodType dstType = typeForm.erasedType();
1837 classFilePrologue();
1866 String targetDesc = dstType.basicType().toMethodDescriptorString();
1867 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc, false);
1868
1869 // Box primitive types
1870 Class<?> rtype = dstType.returnType();
1871 if (rtype != void.class && rtype.isPrimitive()) {
1872 Wrapper srcWrapper = Wrapper.forBasicType(rtype);
1873 Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper; // widen subword to int
1874 // boolean casts not allowed
1875 emitPrimCast(srcWrapper, dstWrapper);
1876 emitBoxing(dstWrapper);
1877 }
1878
1879 // If the return type is void we return a null reference.
1880 if (rtype == void.class) {
1881 mv.visitInsn(Opcodes.ACONST_NULL);
1882 }
1883 emitReturnInsn(L_TYPE); // NOTE: NamedFunction invokers always return a reference value.
1884
1885 methodEpilogue();
1886 bogusMethod(dstType);
1887
1888 final byte[] classFile = cw.toByteArray();
1889 maybeDump(classFile);
1890 return classFile;
1891 }
1892
1893 /**
1894 * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
1895 * for debugging purposes.
1896 */
1897 private void bogusMethod(Object os) {
1898 if (DUMP_CLASS_FILES) {
1899 mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
1900 mv.visitLdcInsn(os.toString());
1901 mv.visitInsn(Opcodes.POP);
1902 mv.visitInsn(Opcodes.RETURN);
1903 mv.visitMaxs(0, 0);
1904 mv.visitEnd();
1905 }
|
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
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.org.objectweb.asm.ClassWriter;
29 import jdk.internal.org.objectweb.asm.FieldVisitor;
30 import jdk.internal.org.objectweb.asm.Label;
31 import jdk.internal.org.objectweb.asm.MethodVisitor;
32 import jdk.internal.org.objectweb.asm.Opcodes;
33 import jdk.internal.org.objectweb.asm.Type;
34 import sun.invoke.util.VerifyAccess;
35 import sun.invoke.util.VerifyType;
36 import sun.invoke.util.Wrapper;
37 import sun.reflect.misc.ReflectUtil;
38
39 import java.io.File;
40 import java.io.FileOutputStream;
41 import java.io.IOException;
42 import java.lang.reflect.Modifier;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.stream.Stream;
48
49 import static java.lang.invoke.LambdaForm.BasicType;
50 import static java.lang.invoke.LambdaForm.BasicType.*;
51 import static java.lang.invoke.LambdaForm.*;
52 import static java.lang.invoke.MethodHandleNatives.Constants.*;
53 import static java.lang.invoke.MethodHandleStatics.*;
54 import static java.lang.invoke.MethodHandles.Lookup.*;
55
56 /**
57 * Code generation backend for LambdaForm.
58 * <p>
59 * @author John Rose, JSR 292 EG
60 */
61 class InvokerBytecodeGenerator {
62 /** Define class names for convenience. */
63 private static final String MH = "java/lang/invoke/MethodHandle";
64 private static final String MHI = "java/lang/invoke/MethodHandleImpl";
65 private static final String LF = "java/lang/invoke/LambdaForm";
66 private static final String LFN = "java/lang/invoke/LambdaForm$Name";
67 private static final String CLS = "java/lang/Class";
68 private static final String OBJ = "java/lang/Object";
69 private static final String OBJARY = "[Ljava/lang/Object;";
70
71 private static final String LOOP_CLAUSES = MHI + "$LoopClauses";
72 private static final String MHARY2 = "[[L" + MH + ";";
73 private static final String MH_SIG = "L" + MH + ";";
74
75
76 private static final String LF_SIG = "L" + LF + ";";
77 private static final String LFN_SIG = "L" + LFN + ";";
78 private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";";
79 private static final String LLV_SIG = "(L" + OBJ + ";L" + OBJ + ";)V";
80 private static final String CLASS_PREFIX = LF + "$";
81 private static final String SOURCE_PREFIX = "LambdaForm$";
82
83 /** Name of its super class*/
84 static final String INVOKER_SUPER_NAME = OBJ;
85
86 /** Name of new class */
87 private final String className;
88
89 private final LambdaForm lambdaForm;
90 private final String invokerName;
91 private final MethodType invokerType;
92
93 /** Info about local variables in compiled lambda form */
94 private int[] localsMap; // index
95 private Class<?>[] localClasses; // type
96
97 /** ASM bytecode generation. */
98 private ClassWriter cw;
99 private MethodVisitor mv;
100 private final List<ClassData> classData = new ArrayList<>();
101
102 /** Single element internal class name lookup cache. */
103 private Class<?> lastClass;
104 private String lastInternalName;
105
106 private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
107 private static final Class<?> HOST_CLASS = LambdaForm.class;
108 private static final MethodHandles.Lookup LOOKUP = lookup();
109
110 private static MethodHandles.Lookup lookup() {
111 try {
112 return MethodHandles.privateLookupIn(HOST_CLASS, IMPL_LOOKUP);
113 } catch (IllegalAccessException e) {
114 throw newInternalError(e);
115 }
116 }
117
118 /** Main constructor; other constructors delegate to this one. */
119 private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
120 String className, String invokerName, MethodType invokerType) {
121 int p = invokerName.indexOf('.');
122 if (p > -1) {
123 className = invokerName.substring(0, p);
124 invokerName = invokerName.substring(p + 1);
125 }
126 if (DUMP_CLASS_FILES) {
127 className = makeDumpableClassName(className);
128 }
129 this.className = className;
130 this.lambdaForm = lambdaForm;
131 this.invokerName = invokerName;
132 this.invokerType = invokerType;
133 this.localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots
134 this.localClasses = new Class<?>[localsMapSize+1];
135 }
136
219 }
220 }
221 });
222 }
223 }
224
225 private static String makeDumpableClassName(String className) {
226 Integer ctr;
227 synchronized (DUMP_CLASS_FILES_COUNTERS) {
228 ctr = DUMP_CLASS_FILES_COUNTERS.get(className);
229 if (ctr == null) ctr = 0;
230 DUMP_CLASS_FILES_COUNTERS.put(className, ctr+1);
231 }
232 String sfx = ctr.toString();
233 while (sfx.length() < 3)
234 sfx = "0"+sfx;
235 className += sfx;
236 return className;
237 }
238
239 public static class ClassData {
240 final String name;
241 final String desc;
242 final Object value;
243
244 ClassData(String name, String desc, Object value) {
245 this.name = name;
246 this.desc = desc;
247 this.value = value;
248 }
249
250 public String name() { return name; }
251 public String toString() {
252 return name + ",value="+value;
253 }
254 }
255
256 String classData(Object arg) {
257 String desc;
258 if (arg instanceof Class) {
259 desc = "Ljava/lang/Class;";
260 } else if (arg instanceof MethodHandle) {
261 desc = MH_SIG;
262 } else if (arg instanceof LambdaForm) {
263 desc = LF_SIG;
264 } else {
265 desc = "Ljava/lang/Object;";
266 }
267
268 Class<?> c = arg.getClass();
269 while (c.isArray()) {
270 c = c.getComponentType();
271 }
272 // unique static variable name
273 String name = "_DATA_" + c.getSimpleName() + "_" + classData.size();
274 ClassData cd = new ClassData(name, desc, arg);
275 classData.add(cd);
276 return cd.name();
277 }
278
279 List<Object> classDataValues() {
280 Object[] data = new Object[classData.size()];
281 for (int i = 0; i < classData.size(); i++) {
282 data[i] = classData.get(i).value;
283 }
284 return List.of(data);
285 }
286
287 private static String debugString(Object arg) {
288 if (arg instanceof MethodHandle) {
289 MethodHandle mh = (MethodHandle) arg;
290 MemberName member = mh.internalMemberName();
291 if (member != null)
292 return member.toString();
293 return mh.debugString();
294 }
295 return arg.toString();
296 }
297
298 /**
299 * Extract the number of constant pool entries from a given class file.
300 *
301 * @param classFile the bytes of the class file in question.
302 * @return the number of entries in the constant pool.
303 */
304 private static int getConstantPoolSize(byte[] classFile) {
305 // The first few bytes:
306 // u4 magic;
307 // u2 minor_version;
308 // u2 major_version;
309 // u2 constant_pool_count;
310 return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
311 }
312
313 /**
314 * Extract the MemberName of a newly-defined method.
315 */
316 private MemberName loadMethod(byte[] classFile) {
317 Class<?> invokerClass = LOOKUP.makeHiddenClassDefiner(classFile)
318 .defineClass(true, classDataValues());
319 return resolveInvokerMember(invokerClass, invokerName, invokerType);
320 }
321
322 private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
323 MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
324 try {
325 member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class);
326 } catch (ReflectiveOperationException e) {
327 throw newInternalError(e);
328 }
329 return member;
330 }
331
332 /**
333 * Set up class file generation.
334 */
335 private ClassWriter classFilePrologue() {
336 final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC
337 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
338 setClassWriter(cw);
339 cw.visit(Opcodes.V1_8, NOT_ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
340 CLASS_PREFIX + className, null, INVOKER_SUPER_NAME, null);
341 cw.visitSource(SOURCE_PREFIX + className, null);
342 return cw;
343 }
344
345 private void methodPrologue() {
346 String invokerDesc = invokerType.toMethodDescriptorString();
347 mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
348 }
349
350 /**
351 * Tear down class file generation.
352 */
353 private void methodEpilogue() {
354 mv.visitMaxs(0, 0);
355 mv.visitEnd();
356 }
357
358 private String className() {
359 return CLASS_PREFIX + className;
360 }
361
362 private void clinit() {
363 clinit(cw, className(), classData);
364 }
365
366 /*
367 * <clinit> to initialize the static final fields with the live class data
368 * LambdaForms can't use condy due to bootstrapping issue.
369 */
370 static void clinit(ClassWriter cw, String className, List<ClassData> classData) {
371 if (classData.isEmpty())
372 return;
373
374 for (ClassData p : classData) {
375 // add the static field
376 FieldVisitor fv = cw.visitField(Opcodes.ACC_STATIC|Opcodes.ACC_FINAL, p.name, p.desc, null, null);
377 fv.visitEnd();
378 }
379
380 MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
381 mv.visitCode();
382 mv.visitLdcInsn(Type.getType("L" + className + ";"));
383 mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/invoke/MethodHandleNatives",
384 "classData", "(Ljava/lang/Class;)Ljava/lang/Object;", false);
385 // we should optimize one single element case that does not need to create a List
386 mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/List");
387 mv.visitVarInsn(Opcodes.ASTORE, 0);
388 int index = 0;
389 for (ClassData p : classData) {
390 // initialize the static field
391 mv.visitVarInsn(Opcodes.ALOAD, 0);
392 emitIconstInsn(mv, index++);
393 mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/List",
394 "get", "(I)Ljava/lang/Object;", true);
395 mv.visitTypeInsn(Opcodes.CHECKCAST, p.desc.substring(1, p.desc.length()-1));
396 mv.visitFieldInsn(Opcodes.PUTSTATIC, className, p.name, p.desc);
397 }
398 mv.visitInsn(Opcodes.RETURN);
399 mv.visitMaxs(2, 1);
400 mv.visitEnd();
401 }
402
403 /*
404 * Low-level emit helpers.
405 */
406 private void emitConst(Object con) {
407 if (con == null) {
408 mv.visitInsn(Opcodes.ACONST_NULL);
409 return;
410 }
411 if (con instanceof Integer) {
412 emitIconstInsn((int) con);
413 return;
414 }
415 if (con instanceof Byte) {
416 emitIconstInsn((byte)con);
417 return;
418 }
419 if (con instanceof Short) {
420 emitIconstInsn((short)con);
421 return;
422 }
455 short sx = (short)x;
456 if (x == sx) {
457 if (sx >= 0 && sx <= 1) {
458 mv.visitInsn(Opcodes.DCONST_0 + (int) sx);
459 } else {
460 emitIconstInsn((int) x);
461 mv.visitInsn(Opcodes.I2D);
462 }
463 return;
464 }
465 }
466 if (con instanceof Boolean) {
467 emitIconstInsn((boolean) con ? 1 : 0);
468 return;
469 }
470 // fall through:
471 mv.visitLdcInsn(con);
472 }
473
474 private void emitIconstInsn(final int cst) {
475 emitIconstInsn(mv, cst);
476 }
477
478 private static void emitIconstInsn(MethodVisitor mv, int cst) {
479 if (cst >= -1 && cst <= 5) {
480 mv.visitInsn(Opcodes.ICONST_0 + cst);
481 } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
482 mv.visitIntInsn(Opcodes.BIPUSH, cst);
483 } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
484 mv.visitIntInsn(Opcodes.SIPUSH, cst);
485 } else {
486 mv.visitLdcInsn(cst);
487 }
488 }
489
490 /*
491 * NOTE: These load/store methods use the localsMap to find the correct index!
492 */
493 private void emitLoadInsn(BasicType type, int index) {
494 int opcode = loadInsnOpcode(type);
495 mv.visitVarInsn(opcode, localsMap[index]);
496 }
497
498 private int loadInsnOpcode(BasicType type) throws InternalError {
628 }
629 return false;
630 }
631
632 private void emitReferenceCast(Class<?> cls, Object arg) {
633 Name writeBack = null; // local to write back result
634 if (arg instanceof Name) {
635 Name n = (Name) arg;
636 if (lambdaForm.useCount(n) > 1) {
637 // This guy gets used more than once.
638 writeBack = n;
639 if (assertStaticType(cls, n)) {
640 return; // this cast was already performed
641 }
642 }
643 }
644 if (isStaticallyNameable(cls)) {
645 String sig = getInternalName(cls);
646 mv.visitTypeInsn(Opcodes.CHECKCAST, sig);
647 } else {
648 mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(cls), "Ljava/lang/Class;");
649 mv.visitInsn(Opcodes.SWAP);
650 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CLS, "cast", LL_SIG, false);
651 if (Object[].class.isAssignableFrom(cls))
652 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
653 else if (PROFILE_LEVEL > 0)
654 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ);
655 }
656 if (writeBack != null) {
657 mv.visitInsn(Opcodes.DUP);
658 emitAstoreInsn(writeBack.index());
659 }
660 }
661
662 /**
663 * Emits an actual return instruction conforming to the given return type.
664 */
665 private void emitReturnInsn(BasicType type) {
666 int opcode;
667 switch (type) {
668 case I_TYPE: opcode = Opcodes.IRETURN; break;
787 try {
788 Class<?> c = Class.forName(tp.getClassName(), false, null);
789 return true;
790 } catch (ClassNotFoundException e) {
791 return false;
792 }
793 }
794
795 static final String DONTINLINE_SIG = className("Ljdk/internal/vm/annotation/DontInline;");
796 static final String FORCEINLINE_SIG = className("Ljdk/internal/vm/annotation/ForceInline;");
797 static final String HIDDEN_SIG = className("Ljdk/internal/vm/annotation/Hidden;");
798 static final String INJECTEDPROFILE_SIG = className("Ljava/lang/invoke/InjectedProfile;");
799 static final String LF_COMPILED_SIG = className("Ljava/lang/invoke/LambdaForm$Compiled;");
800
801 /**
802 * Generate an invoker method for the passed {@link LambdaForm}.
803 */
804 private byte[] generateCustomizedCodeBytes() {
805 classFilePrologue();
806 addMethod();
807 clinit();
808 bogusMethod(lambdaForm);
809
810 final byte[] classFile = toByteArray();
811 maybeDump(classFile);
812 return classFile;
813 }
814
815 void setClassWriter(ClassWriter cw) {
816 this.cw = cw;
817 }
818
819 void addMethod() {
820 methodPrologue();
821
822 // Suppress this method in backtraces displayed to the user.
823 mv.visitAnnotation(HIDDEN_SIG, true);
824
825 // Mark this method as a compiled LambdaForm
826 mv.visitAnnotation(LF_COMPILED_SIG, true);
827
828 if (lambdaForm.forceInline) {
829 // Force inlining of this invoker method.
830 mv.visitAnnotation(FORCEINLINE_SIG, true);
831 } else {
832 mv.visitAnnotation(DONTINLINE_SIG, true);
833 }
834
835 classData(lambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled.
836
837 if (lambdaForm.customized != null) {
838 // Since LambdaForm is customized for a particular MethodHandle, it's safe to substitute
839 // receiver MethodHandle (at slot #0) with an embedded constant and use it instead.
840 // It enables more efficient code generation in some situations, since embedded constants
841 // are compile-time constants for JIT compiler.
842 mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(lambdaForm.customized), MH_SIG);
843 mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
844 assert(checkActualReceiver()); // expects MethodHandle on top of the stack
845 mv.visitVarInsn(Opcodes.ASTORE, localsMap[0]);
846 }
847
848 // iterate over the form's names, generating bytecode instructions for each
849 // start iterating at the first name following the arguments
850 Name onStack = null;
851 for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
852 Name name = lambdaForm.names[i];
853
854 emitStoreResult(onStack);
855 onStack = name; // unless otherwise modified below
856 MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
857 switch (intr) {
858 case SELECT_ALTERNATIVE:
859 assert lambdaForm.isSelectAlternative(i);
860 if (PROFILE_GWT) {
861 assert(name.arguments[0] instanceof Name &&
862 ((Name)name.arguments[0]).refersTo(MethodHandleImpl.class, "profileBoolean"));
952 assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE || arrayOpcode == Opcodes.ARRAYLENGTH;
953 Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
954 assert elementType != null;
955 emitPushArguments(name, 0);
956 if (arrayOpcode != Opcodes.ARRAYLENGTH && elementType.isPrimitive()) {
957 Wrapper w = Wrapper.forPrimitiveType(elementType);
958 arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
959 }
960 mv.visitInsn(arrayOpcode);
961 }
962
963 /**
964 * Emit an invoke for the given name.
965 */
966 void emitInvoke(Name name) {
967 assert(!name.isLinkerMethodInvoke()); // should use the static path for these
968 if (true) {
969 // push receiver
970 MethodHandle target = name.function.resolvedHandle();
971 assert(target != null) : name.exprString();
972 mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(target), MH_SIG);
973 emitReferenceCast(MethodHandle.class, target);
974 } else {
975 // load receiver
976 emitAloadInsn(0);
977 emitReferenceCast(MethodHandle.class, null);
978 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
979 mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
980 // TODO more to come
981 }
982
983 // push arguments
984 emitPushArguments(name, 0);
985
986 // invocation
987 MethodType type = name.function.methodType();
988 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
989 }
990
991 private static Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
992 // Sample classes from each package we are willing to bind to statically:
1008 static boolean isStaticallyInvocable(Name name) {
1009 return isStaticallyInvocable(name.function.member());
1010 }
1011
1012 static boolean isStaticallyInvocable(MemberName member) {
1013 if (member == null) return false;
1014 if (member.isConstructor()) return false;
1015 Class<?> cls = member.getDeclaringClass();
1016 // Fast-path non-private members declared by MethodHandles, which is a common
1017 // case
1018 if (MethodHandle.class.isAssignableFrom(cls) && !member.isPrivate()) {
1019 assert(isStaticallyInvocableType(member.getMethodOrFieldType()));
1020 return true;
1021 }
1022 if (cls.isArray() || cls.isPrimitive())
1023 return false; // FIXME
1024 if (cls.isAnonymousClass() || cls.isLocalClass())
1025 return false; // inner class of some sort
1026 if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
1027 return false; // not on BCP
1028 if (cls.isHidden())
1029 return false;
1030 if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: Unsafe::defineAnonymousClass to be removed
1031 return false;
1032 if (!isStaticallyInvocableType(member.getMethodOrFieldType()))
1033 return false;
1034 if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
1035 return true; // in java.lang.invoke package
1036 if (member.isPublic() && isStaticallyNameable(cls))
1037 return true;
1038 return false;
1039 }
1040
1041 private static boolean isStaticallyInvocableType(MethodType mtype) {
1042 if (!isStaticallyNameable(mtype.returnType()))
1043 return false;
1044 for (Class<?> ptype : mtype.parameterArray())
1045 if (!isStaticallyNameable(ptype))
1046 return false;
1047 return true;
1048 }
1049
1050 static boolean isStaticallyNameable(Class<?> cls) {
1051 if (cls == Object.class)
1052 return true;
1053 if (MethodHandle.class.isAssignableFrom(cls)) {
1054 assert(!cls.isHidden());
1055 return true;
1056 }
1057 while (cls.isArray())
1058 cls = cls.getComponentType();
1059 if (cls.isPrimitive())
1060 return true; // int[].class, for example
1061 if (cls.isHidden())
1062 return false;
1063 if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: Unsafe::defineAnonymousClass to be removed
1064 return false;
1065 // could use VerifyAccess.isClassAccessible but the following is a safe approximation
1066 if (cls.getClassLoader() != Object.class.getClassLoader())
1067 return false;
1068 if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
1069 return true;
1070 if (!Modifier.isPublic(cls.getModifiers()))
1071 return false;
1072 for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
1073 if (VerifyAccess.isSamePackage(pkgcls, cls))
1074 return true;
1075 }
1076 return false;
1077 }
1078
1079 void emitStaticInvoke(Name name) {
1080 emitStaticInvoke(name.function.member(), name);
1081 }
1082
1083 /**
1115 Class<?> rtype = member.getInvocationType().returnType();
1116 assert(!rtype.isPrimitive());
1117 if (rtype != Object.class && !rtype.isInterface()) {
1118 assertStaticType(rtype, name);
1119 }
1120 }
1121 }
1122
1123 void emitNewArray(Name name) throws InternalError {
1124 Class<?> rtype = name.function.methodType().returnType();
1125 if (name.arguments.length == 0) {
1126 // The array will be a constant.
1127 Object emptyArray;
1128 try {
1129 emptyArray = name.function.resolvedHandle().invoke();
1130 } catch (Throwable ex) {
1131 throw uncaughtException(ex);
1132 }
1133 assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
1134 assert(emptyArray.getClass() == rtype); // exact typing
1135 mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(emptyArray), "Ljava/lang/Object;");
1136 emitReferenceCast(rtype, emptyArray);
1137 return;
1138 }
1139 Class<?> arrayElementType = rtype.getComponentType();
1140 assert(arrayElementType != null);
1141 emitIconstInsn(name.arguments.length);
1142 int xas = Opcodes.AASTORE;
1143 if (!arrayElementType.isPrimitive()) {
1144 mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
1145 } else {
1146 byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
1147 xas = arrayInsnOpcode(tc, xas);
1148 mv.visitIntInsn(Opcodes.NEWARRAY, tc);
1149 }
1150 // store arguments
1151 for (int i = 0; i < name.arguments.length; i++) {
1152 mv.visitInsn(Opcodes.DUP);
1153 emitIconstInsn(i);
1154 emitPushArgument(name, i);
1155 mv.visitInsn(xas);
1678 }
1679
1680 private void emitPushArgument(Name name, int paramIndex) {
1681 Object arg = name.arguments[paramIndex];
1682 Class<?> ptype = name.function.methodType().parameterType(paramIndex);
1683 emitPushArgument(ptype, arg);
1684 }
1685
1686 private void emitPushArgument(Class<?> ptype, Object arg) {
1687 BasicType bptype = basicType(ptype);
1688 if (arg instanceof Name) {
1689 Name n = (Name) arg;
1690 emitLoadInsn(n.type, n.index());
1691 emitImplicitConversion(n.type, ptype, n);
1692 } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
1693 emitConst(arg);
1694 } else {
1695 if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
1696 emitConst(arg);
1697 } else {
1698 mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(arg), "Ljava/lang/Object;");
1699 emitImplicitConversion(L_TYPE, ptype, arg);
1700 }
1701 }
1702 }
1703
1704 /**
1705 * Store the name to its local, if necessary.
1706 */
1707 private void emitStoreResult(Name name) {
1708 if (name != null && name.type != V_TYPE) {
1709 // non-void: actually assign
1710 emitStoreInsn(name.type, name.index());
1711 }
1712 }
1713
1714 /**
1715 * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
1716 */
1717 private void emitReturn(Name onStack) {
1718 // return statement
1870 emitBoxing(Wrapper.forPrimitiveType(ptype));
1871 }
1872 mv.visitInsn(Opcodes.AASTORE);
1873 }
1874 // invoke
1875 emitAloadInsn(0);
1876 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
1877 mv.visitInsn(Opcodes.SWAP); // swap form and array; avoid local variable
1878 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
1879
1880 // maybe unbox
1881 Class<?> rtype = invokerType.returnType();
1882 if (rtype.isPrimitive() && rtype != void.class) {
1883 emitUnboxing(Wrapper.forPrimitiveType(rtype));
1884 }
1885
1886 // return statement
1887 emitReturnInsn(basicType(rtype));
1888
1889 methodEpilogue();
1890 clinit();
1891 bogusMethod(invokerType);
1892
1893 final byte[] classFile = cw.toByteArray();
1894 maybeDump(classFile);
1895 return classFile;
1896 }
1897
1898 /**
1899 * Generate bytecode for a NamedFunction invoker.
1900 */
1901 static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
1902 MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
1903 String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
1904 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
1905 return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
1906 }
1907
1908 private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
1909 MethodType dstType = typeForm.erasedType();
1910 classFilePrologue();
1939 String targetDesc = dstType.basicType().toMethodDescriptorString();
1940 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc, false);
1941
1942 // Box primitive types
1943 Class<?> rtype = dstType.returnType();
1944 if (rtype != void.class && rtype.isPrimitive()) {
1945 Wrapper srcWrapper = Wrapper.forBasicType(rtype);
1946 Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper; // widen subword to int
1947 // boolean casts not allowed
1948 emitPrimCast(srcWrapper, dstWrapper);
1949 emitBoxing(dstWrapper);
1950 }
1951
1952 // If the return type is void we return a null reference.
1953 if (rtype == void.class) {
1954 mv.visitInsn(Opcodes.ACONST_NULL);
1955 }
1956 emitReturnInsn(L_TYPE); // NOTE: NamedFunction invokers always return a reference value.
1957
1958 methodEpilogue();
1959 clinit();
1960 bogusMethod(dstType);
1961
1962 final byte[] classFile = cw.toByteArray();
1963 maybeDump(classFile);
1964 return classFile;
1965 }
1966
1967 /**
1968 * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
1969 * for debugging purposes.
1970 */
1971 private void bogusMethod(Object os) {
1972 if (DUMP_CLASS_FILES) {
1973 mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
1974 mv.visitLdcInsn(os.toString());
1975 mv.visitInsn(Opcodes.POP);
1976 mv.visitInsn(Opcodes.RETURN);
1977 mv.visitMaxs(0, 0);
1978 mv.visitEnd();
1979 }
|