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.Set;
48 import java.util.stream.Stream;
49
50 import static java.lang.invoke.LambdaForm.BasicType;
51 import static java.lang.invoke.LambdaForm.BasicType.*;
52 import static java.lang.invoke.LambdaForm.*;
53 import static java.lang.invoke.MethodHandleNatives.Constants.*;
54 import static java.lang.invoke.MethodHandleStatics.*;
55 import static java.lang.invoke.MethodHandles.Lookup.*;
56
57 /**
58 * Code generation backend for LambdaForm.
59 * <p>
60 * @author John Rose, JSR 292 EG
61 */
62 class InvokerBytecodeGenerator {
63 /** Define class names for convenience. */
64 private static final String MH = "java/lang/invoke/MethodHandle";
65 private static final String MHI = "java/lang/invoke/MethodHandleImpl";
66 private static final String LF = "java/lang/invoke/LambdaForm";
67 private static final String LFN = "java/lang/invoke/LambdaForm$Name";
68 private static final String CLS = "java/lang/Class";
69 private static final String OBJ = "java/lang/Object";
70 private static final String OBJARY = "[Ljava/lang/Object;";
71
72 private static final String LOOP_CLAUSES = MHI + "$LoopClauses";
73 private static final String MHARY2 = "[[L" + MH + ";";
74 private static final String MH_SIG = "L" + MH + ";";
75
76
77 private static final String LF_SIG = "L" + LF + ";";
78 private static final String LFN_SIG = "L" + LFN + ";";
79 private static final String LL_SIG = "(L" + OBJ + ";)L" + OBJ + ";";
80 private static final String LLV_SIG = "(L" + OBJ + ";L" + OBJ + ";)V";
81 private static final String CLASS_PREFIX = LF + "$";
82 private static final String SOURCE_PREFIX = "LambdaForm$";
83
84 /** Name of its super class*/
85 static final String INVOKER_SUPER_NAME = OBJ;
86
87 /** Name of new class */
88 private final String className;
89
90 private final LambdaForm lambdaForm;
91 private final String invokerName;
92 private final MethodType invokerType;
93
94 /** Info about local variables in compiled lambda form */
95 private int[] localsMap; // index
96 private Class<?>[] localClasses; // type
97
98 /** ASM bytecode generation. */
99 private ClassWriter cw;
100 private MethodVisitor mv;
101 private final List<ClassData> classData = new ArrayList<>();
102
103 /** Single element internal class name lookup cache. */
104 private Class<?> lastClass;
105 private String lastInternalName;
106
107 private static final MemberName.Factory MEMBERNAME_FACTORY = MemberName.getFactory();
108 private static final Class<?> HOST_CLASS = LambdaForm.class;
109 private static final MethodHandles.Lookup LOOKUP = lookup();
110
111 private static MethodHandles.Lookup lookup() {
112 try {
113 return MethodHandles.privateLookupIn(HOST_CLASS, IMPL_LOOKUP);
114 } catch (IllegalAccessException e) {
115 throw newInternalError(e);
116 }
117 }
118
119 /** Main constructor; other constructors delegate to this one. */
120 private InvokerBytecodeGenerator(LambdaForm lambdaForm, int localsMapSize,
121 String className, String invokerName, MethodType invokerType) {
122 int p = invokerName.indexOf('.');
123 if (p > -1) {
124 className = invokerName.substring(0, p);
125 invokerName = invokerName.substring(p + 1);
126 }
127 if (DUMP_CLASS_FILES) {
128 className = makeDumpableClassName(className);
129 }
130 this.className = className;
131 this.lambdaForm = lambdaForm;
132 this.invokerName = invokerName;
133 this.invokerType = invokerType;
134 this.localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots
135 this.localClasses = new Class<?>[localsMapSize+1];
136 }
137
220 }
221 }
222 });
223 }
224 }
225
226 private static String makeDumpableClassName(String className) {
227 Integer ctr;
228 synchronized (DUMP_CLASS_FILES_COUNTERS) {
229 ctr = DUMP_CLASS_FILES_COUNTERS.get(className);
230 if (ctr == null) ctr = 0;
231 DUMP_CLASS_FILES_COUNTERS.put(className, ctr+1);
232 }
233 String sfx = ctr.toString();
234 while (sfx.length() < 3)
235 sfx = "0"+sfx;
236 className += sfx;
237 return className;
238 }
239
240 public static class ClassData {
241 final String name;
242 final String desc;
243 final Object value;
244
245 ClassData(String name, String desc, Object value) {
246 this.name = name;
247 this.desc = desc;
248 this.value = value;
249 }
250
251 public String name() { return name; }
252 public String toString() {
253 return name + ",value="+value;
254 }
255 }
256
257 String classData(Object arg) {
258 String desc;
259 if (arg instanceof Class) {
260 desc = "Ljava/lang/Class;";
261 } else if (arg instanceof MethodHandle) {
262 desc = MH_SIG;
263 } else if (arg instanceof LambdaForm) {
264 desc = LF_SIG;
265 } else {
266 desc = "Ljava/lang/Object;";
267 }
268
269 Class<?> c = arg.getClass();
270 while (c.isArray()) {
271 c = c.getComponentType();
272 }
273 // unique static variable name
274 String name = "_DATA_" + c.getSimpleName() + "_" + classData.size();
275 ClassData cd = new ClassData(name, desc, arg);
276 classData.add(cd);
277 return cd.name();
278 }
279
280 List<Object> classDataValues() {
281 Object[] data = new Object[classData.size()];
282 for (int i = 0; i < classData.size(); i++) {
283 data[i] = classData.get(i).value;
284 }
285 return List.of(data);
286 }
287
288 private static String debugString(Object arg) {
289 if (arg instanceof MethodHandle) {
290 MethodHandle mh = (MethodHandle) arg;
291 MemberName member = mh.internalMemberName();
292 if (member != null)
293 return member.toString();
294 return mh.debugString();
295 }
296 return arg.toString();
297 }
298
299 /**
300 * Extract the number of constant pool entries from a given class file.
301 *
302 * @param classFile the bytes of the class file in question.
303 * @return the number of entries in the constant pool.
304 */
305 private static int getConstantPoolSize(byte[] classFile) {
306 // The first few bytes:
307 // u4 magic;
308 // u2 minor_version;
309 // u2 major_version;
310 // u2 constant_pool_count;
311 return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
312 }
313
314 /**
315 * Extract the MemberName of a newly-defined method.
316 */
317 private MemberName loadMethod(byte[] classFile) {
318 Class<?> invokerClass = LOOKUP.makeHiddenClassDefiner(classFile, Set.of(ClassOption.WEAK))
319 .defineClass(true, classDataValues());
320 return resolveInvokerMember(invokerClass, invokerName, invokerType);
321 }
322
323 private static MemberName resolveInvokerMember(Class<?> invokerClass, String name, MethodType type) {
324 MemberName member = new MemberName(invokerClass, name, type, REF_invokeStatic);
325 try {
326 member = MEMBERNAME_FACTORY.resolveOrFail(REF_invokeStatic, member, HOST_CLASS, ReflectiveOperationException.class);
327 } catch (ReflectiveOperationException e) {
328 throw newInternalError(e);
329 }
330 return member;
331 }
332
333 /**
334 * Set up class file generation.
335 */
336 private ClassWriter classFilePrologue() {
337 final int NOT_ACC_PUBLIC = 0; // not ACC_PUBLIC
338 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
339 setClassWriter(cw);
340 cw.visit(Opcodes.V1_8, NOT_ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
341 CLASS_PREFIX + className, null, INVOKER_SUPER_NAME, null);
342 cw.visitSource(SOURCE_PREFIX + className, null);
343 return cw;
344 }
345
346 private void methodPrologue() {
347 String invokerDesc = invokerType.toMethodDescriptorString();
348 mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
349 }
350
351 /**
352 * Tear down class file generation.
353 */
354 private void methodEpilogue() {
355 mv.visitMaxs(0, 0);
356 mv.visitEnd();
357 }
358
359 private String className() {
360 return CLASS_PREFIX + className;
361 }
362
363 private void clinit() {
364 clinit(cw, className(), classData);
365 }
366
367 static void clinit(ClassWriter cw, String className, List<ClassData> classData) {
368 if (classData.isEmpty())
369 return;
370
371 for (ClassData p : classData) {
372 // add the static field
373 FieldVisitor fv = cw.visitField(Opcodes.ACC_STATIC|Opcodes.ACC_FINAL, p.name, p.desc, null, null);
374 fv.visitEnd();
375 }
376
377 MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
378 mv.visitCode();
379 // bootstrapping issue if using condy
380 mv.visitLdcInsn(Type.getType("L" + className + ";"));
381 mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/invoke/MethodHandleNatives",
382 "classData", "(Ljava/lang/Class;)Ljava/lang/Object;", false);
383 // we should optimize one single element case that does not need to create a List
384 mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/List");
385 mv.visitVarInsn(Opcodes.ASTORE, 0);
386 int index = 0;
387 for (ClassData p : classData) {
388 // initialize the static field
389 mv.visitVarInsn(Opcodes.ALOAD, 0);
390 emitIconstInsn(mv, index++);
391 mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/List",
392 "get", "(I)Ljava/lang/Object;", true);
393 mv.visitTypeInsn(Opcodes.CHECKCAST, p.desc.substring(1, p.desc.length()-1));
394 mv.visitFieldInsn(Opcodes.PUTSTATIC, className, p.name, p.desc);
395 }
396 mv.visitInsn(Opcodes.RETURN);
397 mv.visitMaxs(2, 1);
398 mv.visitEnd();
399 }
400
401 /*
402 * Low-level emit helpers.
403 */
404 private void emitConst(Object con) {
405 if (con == null) {
406 mv.visitInsn(Opcodes.ACONST_NULL);
407 return;
408 }
409 if (con instanceof Integer) {
410 emitIconstInsn((int) con);
411 return;
412 }
413 if (con instanceof Byte) {
414 emitIconstInsn((byte)con);
415 return;
416 }
417 if (con instanceof Short) {
418 emitIconstInsn((short)con);
419 return;
420 }
453 short sx = (short)x;
454 if (x == sx) {
455 if (sx >= 0 && sx <= 1) {
456 mv.visitInsn(Opcodes.DCONST_0 + (int) sx);
457 } else {
458 emitIconstInsn((int) x);
459 mv.visitInsn(Opcodes.I2D);
460 }
461 return;
462 }
463 }
464 if (con instanceof Boolean) {
465 emitIconstInsn((boolean) con ? 1 : 0);
466 return;
467 }
468 // fall through:
469 mv.visitLdcInsn(con);
470 }
471
472 private void emitIconstInsn(final int cst) {
473 emitIconstInsn(mv, cst);
474 }
475
476 private static void emitIconstInsn(MethodVisitor mv, int cst) {
477 if (cst >= -1 && cst <= 5) {
478 mv.visitInsn(Opcodes.ICONST_0 + cst);
479 } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
480 mv.visitIntInsn(Opcodes.BIPUSH, cst);
481 } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
482 mv.visitIntInsn(Opcodes.SIPUSH, cst);
483 } else {
484 mv.visitLdcInsn(cst);
485 }
486 }
487
488 /*
489 * NOTE: These load/store methods use the localsMap to find the correct index!
490 */
491 private void emitLoadInsn(BasicType type, int index) {
492 int opcode = loadInsnOpcode(type);
493 mv.visitVarInsn(opcode, localsMap[index]);
494 }
495
496 private int loadInsnOpcode(BasicType type) throws InternalError {
626 }
627 return false;
628 }
629
630 private void emitReferenceCast(Class<?> cls, Object arg) {
631 Name writeBack = null; // local to write back result
632 if (arg instanceof Name) {
633 Name n = (Name) arg;
634 if (lambdaForm.useCount(n) > 1) {
635 // This guy gets used more than once.
636 writeBack = n;
637 if (assertStaticType(cls, n)) {
638 return; // this cast was already performed
639 }
640 }
641 }
642 if (isStaticallyNameable(cls)) {
643 String sig = getInternalName(cls);
644 mv.visitTypeInsn(Opcodes.CHECKCAST, sig);
645 } else {
646 mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(cls), "Ljava/lang/Class;");
647 mv.visitInsn(Opcodes.SWAP);
648 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CLS, "cast", LL_SIG, false);
649 if (Object[].class.isAssignableFrom(cls))
650 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJARY);
651 else if (PROFILE_LEVEL > 0)
652 mv.visitTypeInsn(Opcodes.CHECKCAST, OBJ);
653 }
654 if (writeBack != null) {
655 mv.visitInsn(Opcodes.DUP);
656 emitAstoreInsn(writeBack.index());
657 }
658 }
659
660 /**
661 * Emits an actual return instruction conforming to the given return type.
662 */
663 private void emitReturnInsn(BasicType type) {
664 int opcode;
665 switch (type) {
666 case I_TYPE: opcode = Opcodes.IRETURN; break;
785 try {
786 Class<?> c = Class.forName(tp.getClassName(), false, null);
787 return true;
788 } catch (ClassNotFoundException e) {
789 return false;
790 }
791 }
792
793 static final String DONTINLINE_SIG = className("Ljdk/internal/vm/annotation/DontInline;");
794 static final String FORCEINLINE_SIG = className("Ljdk/internal/vm/annotation/ForceInline;");
795 static final String HIDDEN_SIG = className("Ljdk/internal/vm/annotation/Hidden;");
796 static final String INJECTEDPROFILE_SIG = className("Ljava/lang/invoke/InjectedProfile;");
797 static final String LF_COMPILED_SIG = className("Ljava/lang/invoke/LambdaForm$Compiled;");
798
799 /**
800 * Generate an invoker method for the passed {@link LambdaForm}.
801 */
802 private byte[] generateCustomizedCodeBytes() {
803 classFilePrologue();
804 addMethod();
805 clinit();
806 bogusMethod(lambdaForm);
807
808 final byte[] classFile = toByteArray();
809 maybeDump(classFile);
810 return classFile;
811 }
812
813 void setClassWriter(ClassWriter cw) {
814 this.cw = cw;
815 }
816
817 void addMethod() {
818 methodPrologue();
819
820 // Suppress this method in backtraces displayed to the user.
821 mv.visitAnnotation(HIDDEN_SIG, true);
822
823 // Mark this method as a compiled LambdaForm
824 mv.visitAnnotation(LF_COMPILED_SIG, true);
825
826 if (lambdaForm.forceInline) {
827 // Force inlining of this invoker method.
828 mv.visitAnnotation(FORCEINLINE_SIG, true);
829 } else {
830 mv.visitAnnotation(DONTINLINE_SIG, true);
831 }
832
833 classData(lambdaForm); // keep LambdaForm instance & its compiled form lifetime tightly coupled.
834
835 if (lambdaForm.customized != null) {
836 // Since LambdaForm is customized for a particular MethodHandle, it's safe to substitute
837 // receiver MethodHandle (at slot #0) with an embedded constant and use it instead.
838 // It enables more efficient code generation in some situations, since embedded constants
839 // are compile-time constants for JIT compiler.
840 mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(lambdaForm.customized), MH_SIG);
841 mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
842 assert(checkActualReceiver()); // expects MethodHandle on top of the stack
843 mv.visitVarInsn(Opcodes.ASTORE, localsMap[0]);
844 }
845
846 // iterate over the form's names, generating bytecode instructions for each
847 // start iterating at the first name following the arguments
848 Name onStack = null;
849 for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
850 Name name = lambdaForm.names[i];
851
852 emitStoreResult(onStack);
853 onStack = name; // unless otherwise modified below
854 MethodHandleImpl.Intrinsic intr = name.function.intrinsicName();
855 switch (intr) {
856 case SELECT_ALTERNATIVE:
857 assert lambdaForm.isSelectAlternative(i);
858 if (PROFILE_GWT) {
859 assert(name.arguments[0] instanceof Name &&
860 ((Name)name.arguments[0]).refersTo(MethodHandleImpl.class, "profileBoolean"));
950 assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE || arrayOpcode == Opcodes.ARRAYLENGTH;
951 Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
952 assert elementType != null;
953 emitPushArguments(name, 0);
954 if (arrayOpcode != Opcodes.ARRAYLENGTH && elementType.isPrimitive()) {
955 Wrapper w = Wrapper.forPrimitiveType(elementType);
956 arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
957 }
958 mv.visitInsn(arrayOpcode);
959 }
960
961 /**
962 * Emit an invoke for the given name.
963 */
964 void emitInvoke(Name name) {
965 assert(!name.isLinkerMethodInvoke()); // should use the static path for these
966 if (true) {
967 // push receiver
968 MethodHandle target = name.function.resolvedHandle();
969 assert(target != null) : name.exprString();
970 mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(target), MH_SIG);
971 emitReferenceCast(MethodHandle.class, target);
972 } else {
973 // load receiver
974 emitAloadInsn(0);
975 emitReferenceCast(MethodHandle.class, null);
976 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
977 mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
978 // TODO more to come
979 }
980
981 // push arguments
982 emitPushArguments(name, 0);
983
984 // invocation
985 MethodType type = name.function.methodType();
986 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
987 }
988
989 private static Class<?>[] STATICALLY_INVOCABLE_PACKAGES = {
990 // Sample classes from each package we are willing to bind to statically:
1006 static boolean isStaticallyInvocable(Name name) {
1007 return isStaticallyInvocable(name.function.member());
1008 }
1009
1010 static boolean isStaticallyInvocable(MemberName member) {
1011 if (member == null) return false;
1012 if (member.isConstructor()) return false;
1013 Class<?> cls = member.getDeclaringClass();
1014 // Fast-path non-private members declared by MethodHandles, which is a common
1015 // case
1016 if (MethodHandle.class.isAssignableFrom(cls) && !member.isPrivate()) {
1017 assert(isStaticallyInvocableType(member.getMethodOrFieldType()));
1018 return true;
1019 }
1020 if (cls.isArray() || cls.isPrimitive())
1021 return false; // FIXME
1022 if (cls.isAnonymousClass() || cls.isLocalClass())
1023 return false; // inner class of some sort
1024 if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
1025 return false; // not on BCP
1026 if (cls.isHiddenClass())
1027 return false;
1028 if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: Unsafe::defineAnonymousClass to be removed
1029 return false;
1030 if (!isStaticallyInvocableType(member.getMethodOrFieldType()))
1031 return false;
1032 if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
1033 return true; // in java.lang.invoke package
1034 if (member.isPublic() && isStaticallyNameable(cls))
1035 return true;
1036 return false;
1037 }
1038
1039 private static boolean isStaticallyInvocableType(MethodType mtype) {
1040 if (!isStaticallyNameable(mtype.returnType()))
1041 return false;
1042 for (Class<?> ptype : mtype.parameterArray())
1043 if (!isStaticallyNameable(ptype))
1044 return false;
1045 return true;
1046 }
1047
1048 static boolean isStaticallyNameable(Class<?> cls) {
1049 if (cls == Object.class)
1050 return true;
1051 if (MethodHandle.class.isAssignableFrom(cls)) {
1052 assert(!cls.isHiddenClass());
1053 return true;
1054 }
1055 while (cls.isArray())
1056 cls = cls.getComponentType();
1057 if (cls.isPrimitive())
1058 return true; // int[].class, for example
1059 if (cls.isHiddenClass())
1060 return false;
1061 if (ReflectUtil.isVMAnonymousClass(cls)) // FIXME: Unsafe::defineAnonymousClass to be removed
1062 return false;
1063 // could use VerifyAccess.isClassAccessible but the following is a safe approximation
1064 if (cls.getClassLoader() != Object.class.getClassLoader())
1065 return false;
1066 if (VerifyAccess.isSamePackage(MethodHandle.class, cls))
1067 return true;
1068 if (!Modifier.isPublic(cls.getModifiers()))
1069 return false;
1070 for (Class<?> pkgcls : STATICALLY_INVOCABLE_PACKAGES) {
1071 if (VerifyAccess.isSamePackage(pkgcls, cls))
1072 return true;
1073 }
1074 return false;
1075 }
1076
1077 void emitStaticInvoke(Name name) {
1078 emitStaticInvoke(name.function.member(), name);
1079 }
1080
1081 /**
1113 Class<?> rtype = member.getInvocationType().returnType();
1114 assert(!rtype.isPrimitive());
1115 if (rtype != Object.class && !rtype.isInterface()) {
1116 assertStaticType(rtype, name);
1117 }
1118 }
1119 }
1120
1121 void emitNewArray(Name name) throws InternalError {
1122 Class<?> rtype = name.function.methodType().returnType();
1123 if (name.arguments.length == 0) {
1124 // The array will be a constant.
1125 Object emptyArray;
1126 try {
1127 emptyArray = name.function.resolvedHandle().invoke();
1128 } catch (Throwable ex) {
1129 throw uncaughtException(ex);
1130 }
1131 assert(java.lang.reflect.Array.getLength(emptyArray) == 0);
1132 assert(emptyArray.getClass() == rtype); // exact typing
1133 mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(emptyArray), "Ljava/lang/Object;");
1134 emitReferenceCast(rtype, emptyArray);
1135 return;
1136 }
1137 Class<?> arrayElementType = rtype.getComponentType();
1138 assert(arrayElementType != null);
1139 emitIconstInsn(name.arguments.length);
1140 int xas = Opcodes.AASTORE;
1141 if (!arrayElementType.isPrimitive()) {
1142 mv.visitTypeInsn(Opcodes.ANEWARRAY, getInternalName(arrayElementType));
1143 } else {
1144 byte tc = arrayTypeCode(Wrapper.forPrimitiveType(arrayElementType));
1145 xas = arrayInsnOpcode(tc, xas);
1146 mv.visitIntInsn(Opcodes.NEWARRAY, tc);
1147 }
1148 // store arguments
1149 for (int i = 0; i < name.arguments.length; i++) {
1150 mv.visitInsn(Opcodes.DUP);
1151 emitIconstInsn(i);
1152 emitPushArgument(name, i);
1153 mv.visitInsn(xas);
1676 }
1677
1678 private void emitPushArgument(Name name, int paramIndex) {
1679 Object arg = name.arguments[paramIndex];
1680 Class<?> ptype = name.function.methodType().parameterType(paramIndex);
1681 emitPushArgument(ptype, arg);
1682 }
1683
1684 private void emitPushArgument(Class<?> ptype, Object arg) {
1685 BasicType bptype = basicType(ptype);
1686 if (arg instanceof Name) {
1687 Name n = (Name) arg;
1688 emitLoadInsn(n.type, n.index());
1689 emitImplicitConversion(n.type, ptype, n);
1690 } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
1691 emitConst(arg);
1692 } else {
1693 if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
1694 emitConst(arg);
1695 } else {
1696 mv.visitFieldInsn(Opcodes.GETSTATIC, className(), classData(arg), "Ljava/lang/Object;");
1697 emitImplicitConversion(L_TYPE, ptype, arg);
1698 }
1699 }
1700 }
1701
1702 /**
1703 * Store the name to its local, if necessary.
1704 */
1705 private void emitStoreResult(Name name) {
1706 if (name != null && name.type != V_TYPE) {
1707 // non-void: actually assign
1708 emitStoreInsn(name.type, name.index());
1709 }
1710 }
1711
1712 /**
1713 * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
1714 */
1715 private void emitReturn(Name onStack) {
1716 // return statement
1868 emitBoxing(Wrapper.forPrimitiveType(ptype));
1869 }
1870 mv.visitInsn(Opcodes.AASTORE);
1871 }
1872 // invoke
1873 emitAloadInsn(0);
1874 mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", "Ljava/lang/invoke/LambdaForm;");
1875 mv.visitInsn(Opcodes.SWAP); // swap form and array; avoid local variable
1876 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, LF, "interpretWithArguments", "([Ljava/lang/Object;)Ljava/lang/Object;", false);
1877
1878 // maybe unbox
1879 Class<?> rtype = invokerType.returnType();
1880 if (rtype.isPrimitive() && rtype != void.class) {
1881 emitUnboxing(Wrapper.forPrimitiveType(rtype));
1882 }
1883
1884 // return statement
1885 emitReturnInsn(basicType(rtype));
1886
1887 methodEpilogue();
1888 clinit();
1889 bogusMethod(invokerType);
1890
1891 final byte[] classFile = cw.toByteArray();
1892 maybeDump(classFile);
1893 return classFile;
1894 }
1895
1896 /**
1897 * Generate bytecode for a NamedFunction invoker.
1898 */
1899 static MemberName generateNamedFunctionInvoker(MethodTypeForm typeForm) {
1900 MethodType invokerType = NamedFunction.INVOKER_METHOD_TYPE;
1901 String invokerName = "invoke_" + shortenSignature(basicTypeSignature(typeForm.erasedType()));
1902 InvokerBytecodeGenerator g = new InvokerBytecodeGenerator("NFI", invokerName, invokerType);
1903 return g.loadMethod(g.generateNamedFunctionInvokerImpl(typeForm));
1904 }
1905
1906 private byte[] generateNamedFunctionInvokerImpl(MethodTypeForm typeForm) {
1907 MethodType dstType = typeForm.erasedType();
1908 classFilePrologue();
1937 String targetDesc = dstType.basicType().toMethodDescriptorString();
1938 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", targetDesc, false);
1939
1940 // Box primitive types
1941 Class<?> rtype = dstType.returnType();
1942 if (rtype != void.class && rtype.isPrimitive()) {
1943 Wrapper srcWrapper = Wrapper.forBasicType(rtype);
1944 Wrapper dstWrapper = srcWrapper.isSubwordOrInt() ? Wrapper.INT : srcWrapper; // widen subword to int
1945 // boolean casts not allowed
1946 emitPrimCast(srcWrapper, dstWrapper);
1947 emitBoxing(dstWrapper);
1948 }
1949
1950 // If the return type is void we return a null reference.
1951 if (rtype == void.class) {
1952 mv.visitInsn(Opcodes.ACONST_NULL);
1953 }
1954 emitReturnInsn(L_TYPE); // NOTE: NamedFunction invokers always return a reference value.
1955
1956 methodEpilogue();
1957 clinit();
1958 bogusMethod(dstType);
1959
1960 final byte[] classFile = cw.toByteArray();
1961 maybeDump(classFile);
1962 return classFile;
1963 }
1964
1965 /**
1966 * Emit a bogus method that just loads some string constants. This is to get the constants into the constant pool
1967 * for debugging purposes.
1968 */
1969 private void bogusMethod(Object os) {
1970 if (DUMP_CLASS_FILES) {
1971 mv = cw.visitMethod(Opcodes.ACC_STATIC, "dummy", "()V", null, null);
1972 mv.visitLdcInsn(os.toString());
1973 mv.visitInsn(Opcodes.POP);
1974 mv.visitInsn(Opcodes.RETURN);
1975 mv.visitMaxs(0, 0);
1976 mv.visitEnd();
1977 }
|