1 /*
2 * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
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.misc.CDS;
29 import jdk.internal.org.objectweb.asm.*;
30 import sun.invoke.util.BytecodeDescriptor;
31 import sun.invoke.util.VerifyAccess;
32 import sun.security.action.GetPropertyAction;
33 import sun.security.action.GetBooleanAction;
34
35 import java.io.FilePermission;
36 import java.io.Serializable;
37 import java.lang.constant.ConstantDescs;
38 import java.lang.invoke.MethodHandles.Lookup;
39 import java.lang.reflect.Modifier;
40 import java.security.AccessController;
41 import java.security.PrivilegedAction;
42 import java.util.LinkedHashSet;
43 import java.util.concurrent.atomic.AtomicInteger;
44 import java.util.PropertyPermission;
45 import java.util.Set;
46
47 import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
48 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
49 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
50 import static java.lang.invoke.MethodType.methodType;
51 import static jdk.internal.org.objectweb.asm.Opcodes.*;
52
53 /**
54 * Lambda metafactory implementation which dynamically creates an
55 * inner-class-like class per lambda callsite.
56 *
57 * @see LambdaMetafactory
58 */
59 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
60 private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
61 private static final String JAVA_LANG_OBJECT = "java/lang/Object";
302 * is not found
303 */
304 @SuppressWarnings("removal")
305 private Class<?> generateInnerClass() throws LambdaConversionException {
306 String[] interfaceNames;
307 String interfaceName = interfaceClass.getName().replace('.', '/');
308 boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
309 if (altInterfaces.length == 0) {
310 interfaceNames = new String[]{interfaceName};
311 } else {
312 // Assure no duplicate interfaces (ClassFormatError)
313 Set<String> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
314 itfs.add(interfaceName);
315 for (Class<?> i : altInterfaces) {
316 itfs.add(i.getName().replace('.', '/'));
317 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
318 }
319 interfaceNames = itfs.toArray(new String[itfs.size()]);
320 }
321
322 cw.visit(CLASSFILE_VERSION, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
323 lambdaClassName, null,
324 JAVA_LANG_OBJECT, interfaceNames);
325
326 // Generate final fields to be filled in by constructor
327 for (int i = 0; i < argDescs.length; i++) {
328 FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
329 argNames[i],
330 argDescs[i],
331 null, null);
332 fv.visitEnd();
333 }
334
335 generateConstructor();
336
337 if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
338 generateClassInitializer();
339 }
340
341 // Forward the SAM method
342 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
343 interfaceMethodType.toMethodDescriptorString(), null, null);
344 new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
345
346 // Forward the altMethods
347 if (altMethods != null) {
348 for (MethodType mt : altMethods) {
349 mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
350 mt.toMethodDescriptorString(), null, null);
351 new ForwardingMethodGenerator(mv).generate(mt);
352 }
353 }
354
355 if (isSerializable)
356 generateSerializationFriendlyMethods();
357 else if (accidentallySerializable)
358 generateSerializationHostileMethods();
359
360 cw.visitEnd();
361
362 // Define the generated class in this VM.
363
364 final byte[] classBytes = cw.toByteArray();
365 // If requested, dump out to a file for debugging purposes
366 if (dumper != null) {
367 AccessController.doPrivileged(new PrivilegedAction<>() {
368 @Override
369 public Void run() {
370 dumper.dumpClass(lambdaClassName, classBytes);
371 return null;
372 }
373 }, null,
374 new FilePermission("<<ALL FILES>>", "read, write"),
375 // createDirectories may need it
376 new PropertyPermission("user.dir", "read"));
377 }
378 try {
379 // this class is linked at the indy callsite; so define a hidden nestmate
573 for (int i = 0; i < samParametersLength; i++) {
574 Class<?> argType = samType.parameterType(i);
575 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
576 lvIndex += getParameterSize(argType);
577 convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
578 }
579 }
580
581 private int invocationOpcode() throws InternalError {
582 return switch (implKind) {
583 case MethodHandleInfo.REF_invokeStatic -> INVOKESTATIC;
584 case MethodHandleInfo.REF_newInvokeSpecial -> INVOKESPECIAL;
585 case MethodHandleInfo.REF_invokeVirtual -> INVOKEVIRTUAL;
586 case MethodHandleInfo.REF_invokeInterface -> INVOKEINTERFACE;
587 case MethodHandleInfo.REF_invokeSpecial -> INVOKESPECIAL;
588 default -> throw new InternalError("Unexpected invocation kind: " + implKind);
589 };
590 }
591 }
592
593 static int getParameterSize(Class<?> c) {
594 if (c == Void.TYPE) {
595 return 0;
596 } else if (c == Long.TYPE || c == Double.TYPE) {
597 return 2;
598 }
599 return 1;
600 }
601
602 static int getLoadOpcode(Class<?> c) {
603 if(c == Void.TYPE) {
604 throw new InternalError("Unexpected void type of load opcode");
605 }
606 return ILOAD + getOpcodeOffset(c);
607 }
608
609 static int getReturnOpcode(Class<?> c) {
610 if(c == Void.TYPE) {
611 return RETURN;
612 }
|
1 /*
2 * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
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.misc.PreviewFeatures;
29 import jdk.internal.misc.CDS;
30 import jdk.internal.org.objectweb.asm.*;
31 import sun.invoke.util.BytecodeDescriptor;
32 import sun.invoke.util.VerifyAccess;
33 import sun.security.action.GetPropertyAction;
34 import sun.security.action.GetBooleanAction;
35
36 import java.io.FilePermission;
37 import java.io.Serializable;
38 import java.lang.constant.ConstantDescs;
39 import java.lang.invoke.MethodHandles.Lookup;
40 import java.lang.reflect.Modifier;
41 import java.security.AccessController;
42 import java.security.PrivilegedAction;
43 import java.util.HashSet;
44 import java.util.LinkedHashSet;
45 import java.util.concurrent.atomic.AtomicInteger;
46 import java.util.PropertyPermission;
47 import java.util.Set;
48
49 import static java.lang.invoke.MethodHandleStatics.CLASSFILE_VERSION;
50 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.NESTMATE;
51 import static java.lang.invoke.MethodHandles.Lookup.ClassOption.STRONG;
52 import static java.lang.invoke.MethodType.methodType;
53 import static jdk.internal.org.objectweb.asm.Opcodes.*;
54
55 /**
56 * Lambda metafactory implementation which dynamically creates an
57 * inner-class-like class per lambda callsite.
58 *
59 * @see LambdaMetafactory
60 */
61 /* package */ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory {
62 private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE);
63 private static final String JAVA_LANG_OBJECT = "java/lang/Object";
304 * is not found
305 */
306 @SuppressWarnings("removal")
307 private Class<?> generateInnerClass() throws LambdaConversionException {
308 String[] interfaceNames;
309 String interfaceName = interfaceClass.getName().replace('.', '/');
310 boolean accidentallySerializable = !isSerializable && Serializable.class.isAssignableFrom(interfaceClass);
311 if (altInterfaces.length == 0) {
312 interfaceNames = new String[]{interfaceName};
313 } else {
314 // Assure no duplicate interfaces (ClassFormatError)
315 Set<String> itfs = LinkedHashSet.newLinkedHashSet(altInterfaces.length + 1);
316 itfs.add(interfaceName);
317 for (Class<?> i : altInterfaces) {
318 itfs.add(i.getName().replace('.', '/'));
319 accidentallySerializable |= !isSerializable && Serializable.class.isAssignableFrom(i);
320 }
321 interfaceNames = itfs.toArray(new String[itfs.size()]);
322 }
323
324 int version = CLASSFILE_VERSION | (PreviewFeatures.isEnabled() ? Opcodes.V_PREVIEW : 0);
325 cw.visit(version, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC,
326 lambdaClassName, null,
327 JAVA_LANG_OBJECT, interfaceNames);
328
329 // Generate final fields to be filled in by constructor
330 for (int i = 0; i < argDescs.length; i++) {
331 FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL,
332 argNames[i],
333 argDescs[i],
334 null, null);
335 fv.visitEnd();
336 }
337
338 generateConstructor();
339
340 if (factoryType.parameterCount() == 0 && disableEagerInitialization) {
341 generateClassInitializer();
342 }
343
344 // Forward the SAM method
345 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
346 interfaceMethodType.toMethodDescriptorString(), null, null);
347 new ForwardingMethodGenerator(mv).generate(interfaceMethodType);
348
349 // Forward the altMethods
350 if (altMethods != null) {
351 for (MethodType mt : altMethods) {
352 mv = cw.visitMethod(ACC_PUBLIC, interfaceMethodName,
353 mt.toMethodDescriptorString(), null, null);
354 new ForwardingMethodGenerator(mv).generate(mt);
355 }
356 }
357
358 if (isSerializable)
359 generateSerializationFriendlyMethods();
360 else if (accidentallySerializable)
361 generateSerializationHostileMethods();
362
363 // generate Preload attribute if it references any value class
364 PreloadAttributeBuilder builder = new PreloadAttributeBuilder(targetClass);
365 builder.add(factoryType)
366 .add(interfaceMethodType)
367 .add(implMethodType)
368 .add(dynamicMethodType)
369 .add(altMethods);
370 if (!builder.isEmpty())
371 cw.visitAttribute(builder.build());
372
373 cw.visitEnd();
374
375 // Define the generated class in this VM.
376
377 final byte[] classBytes = cw.toByteArray();
378 // If requested, dump out to a file for debugging purposes
379 if (dumper != null) {
380 AccessController.doPrivileged(new PrivilegedAction<>() {
381 @Override
382 public Void run() {
383 dumper.dumpClass(lambdaClassName, classBytes);
384 return null;
385 }
386 }, null,
387 new FilePermission("<<ALL FILES>>", "read, write"),
388 // createDirectories may need it
389 new PropertyPermission("user.dir", "read"));
390 }
391 try {
392 // this class is linked at the indy callsite; so define a hidden nestmate
586 for (int i = 0; i < samParametersLength; i++) {
587 Class<?> argType = samType.parameterType(i);
588 visitVarInsn(getLoadOpcode(argType), lvIndex + 1);
589 lvIndex += getParameterSize(argType);
590 convertType(argType, implMethodType.parameterType(captureArity + i), dynamicMethodType.parameterType(i));
591 }
592 }
593
594 private int invocationOpcode() throws InternalError {
595 return switch (implKind) {
596 case MethodHandleInfo.REF_invokeStatic -> INVOKESTATIC;
597 case MethodHandleInfo.REF_newInvokeSpecial -> INVOKESPECIAL;
598 case MethodHandleInfo.REF_invokeVirtual -> INVOKEVIRTUAL;
599 case MethodHandleInfo.REF_invokeInterface -> INVOKEINTERFACE;
600 case MethodHandleInfo.REF_invokeSpecial -> INVOKESPECIAL;
601 default -> throw new InternalError("Unexpected invocation kind: " + implKind);
602 };
603 }
604 }
605
606 /*
607 * Preload attribute builder
608 */
609 static class PreloadAttributeBuilder {
610 private final Set<Class<?>> preloadClasses = new HashSet<>();
611 PreloadAttributeBuilder(Class<?> targetClass) {
612 if (requiresPreload(targetClass)) {
613 preloadClasses.add(targetClass);
614 }
615 }
616
617 /*
618 * Add the value types referenced in the given MethodType.
619 */
620 PreloadAttributeBuilder add(MethodType mt) {
621 // parameter types
622 for (Class<?> paramType : mt.ptypes()) {
623 if (requiresPreload(paramType)) {
624 preloadClasses.add(paramType);
625 }
626 }
627 // return type
628 if (requiresPreload(mt.returnType())) {
629 preloadClasses.add(mt.returnType());
630 }
631 return this;
632 }
633
634 PreloadAttributeBuilder add(MethodType... mtypes) {
635 for (MethodType mt : mtypes) {
636 add(mt);
637 }
638 return this;
639 }
640
641 boolean requiresPreload(Class<?> cls) {
642 Class<?> c = cls;
643 while (c.isArray()) {
644 c = c.getComponentType();
645 }
646 return c.isValue();
647 }
648
649 boolean isEmpty() {
650 return preloadClasses.isEmpty();
651 }
652
653 Attribute build() {
654 return new Attribute("Preload") {
655 @Override
656 protected ByteVector write(ClassWriter cw,
657 byte[] code,
658 int len,
659 int maxStack,
660 int maxLocals) {
661 ByteVector attr = new ByteVector();
662 attr.putShort(preloadClasses.size());
663 for (Class<?> c : preloadClasses) {
664 attr.putShort(cw.newClass(Type.getInternalName(c)));
665 }
666 return attr;
667 }
668 };
669 }
670 }
671
672 static int getParameterSize(Class<?> c) {
673 if (c == Void.TYPE) {
674 return 0;
675 } else if (c == Long.TYPE || c == Double.TYPE) {
676 return 2;
677 }
678 return 1;
679 }
680
681 static int getLoadOpcode(Class<?> c) {
682 if(c == Void.TYPE) {
683 throw new InternalError("Unexpected void type of load opcode");
684 }
685 return ILOAD + getOpcodeOffset(c);
686 }
687
688 static int getReturnOpcode(Class<?> c) {
689 if(c == Void.TYPE) {
690 return RETURN;
691 }
|