On Fri, 15 Dec 2023 12:26:50 GMT, Adam Sotona <asot...@openjdk.org> wrote:

>> java.base java.lang.invoke package heavily uses ASM to generate lambdas and 
>> method handles.
>> 
>> This patch converts ASM calls to Classfile API.
>> 
>> This PR is continuation of https://github.com/openjdk/jdk/pull/12945
>> 
>> Any comments and suggestions are welcome.
>> 
>> Please review.
>> 
>> Thank you,
>> Adam
>
> Adam Sotona has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   added missing comment

src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java 
line 318:

> 316:                 accidentallySerializable |= !isSerializable && 
> Serializable.class.isAssignableFrom(i);
> 317:             }
> 318:             interfaces = new ArrayList<>(itfs);

Suggestion:

            interfaces = List.copyOf(itfs);

src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java 
line 406:

> 404:                     public void accept(CodeBuilder cob) {
> 405:                         cob.aload(0)
> 406:                            .invokespecial(CD_Object, INIT_NAME, 
> MethodTypeDesc.of(CD_void));

Suggestion:

                           .invokespecial(CD_Object, INIT_NAME, MTD_void);

src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java 
line 548:

> 546:     static ClassDesc classDesc(Class<?> cls) {
> 547:         return cls.isHidden() ? 
> ClassDesc.ofInternalName(cls.getName().replace('.', '/'))
> 548:                               : 
> ClassDesc.ofDescriptor(cls.descriptorString());

That said, all the usages already anticipate a valid `ClassDesc` that can be 
encoded in bytecode except `implClass`. You should make 2 versions of 
`classDesc()`, one that eagerly throws for all other usages, and another 
special version that handles hidden class conversion (with the same code as 
existing method) for 
https://github.com/openjdk/jdk/pull/17108/files#diff-76236a0dd20022f749d95ad5890e2bece0c4ac212d1b2ffab90ca86875f14282R173

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java line 
468:

> 466:     }
> 467: 
> 468:     private void emitStoreInsn(BasicType type, int index) {

If we are going to use `localsMap` in every removed `emitStoreInsn`, perhaps we 
should restore it instead? Will also make it easier to move away from localsMap 
to CodeBuilder's tracking system.

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java line 
529:

> 527:         // Expects MethodHandle on the stack and actual receiver 
> MethodHandle in slot #0
> 528:         cob.dup()
> 529:            .aload(0)

Note for other reviewers: localsMap[0] is 0 in constructor

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java line 
990:

> 988:         cob.invokevirtual(MRE_Class_isInstance);
> 989:         Label L_rethrow = cob.newLabel();
> 990:         cob.branchInstruction(Opcode.IFEQ, L_rethrow);

Suggestion:

        cob.ifeq(L_rethrow);

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java line 
1002:

> 1000: 
> 1001:         cob.labelBinding(L_rethrow);
> 1002:         cob.throwInstruction();

Suggestion:

        cob.athrow();

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java line 
1131:

> 1129:             emitPopInsn(cob, basicReturnType);
> 1130:         }
> 1131:         cob.throwInstruction();

Suggestion:

        cob.athrow();

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java line 
1145:

> 1143:     private static Opcode popInsnOpcode(BasicType type) {
> 1144:         switch (type) {
> 1145:             case I_TYPE:

Should restore the enhanced switch syntax

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java line 
1171:

> 1169:         
> cob.getfield(ClassDesc.ofInternalName("java/lang/invoke/MethodHandleImpl$CasesHolder"),
>  "cases",
> 1170:                 CD_MethodHandle.arrayType());
> 1171:         int casesLocal = extendLocalsMap(new Class<?>[] { 
> MethodHandle[].class });

We should look into replacing the local map with `CodeBuilder.allocateLocal` 
etc. in the future.

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java line 
1519:

> 1517:         //      double      -     d2i,i2b   d2i,i2s  d2i,i2c    d2i     
>  d2l      d2f      <->
> 1518:         if (from != to && from != TypeKind.BooleanType && to != 
> TypeKind.BooleanType) try {
> 1519:             cob.convertInstruction(from, to);

Need an intermediate int if you are converting from long/float/double to 
byte/short/char.

src/java.base/share/classes/java/lang/invoke/MethodHandles.java line 2290:

> 2288:                 int accessFlags;
> 2289:                 try {
> 2290:                     ClassModel cm = 
> java.lang.classfile.ClassFile.of().parse(bytes);

No need for fully-qualified name.

src/java.base/share/classes/java/lang/invoke/MethodType.java line 1295:

> 1293:     public Optional<MethodTypeDesc> describeConstable() {
> 1294:         try {
> 1295:             var params = new ClassDesc[parameterCount()];

We can probably handle like this:

var retDesc = returnType().describeConstable();
if (retDesc.isEmpty())
    return Optional.empty();

if (parameterCount() == 0)
    return Optional.of(MethodTypeDesc.of(retDesc.get()));

var params = new ClassDesc[parameterCount()];
for (int i = 0; i < params.length; i++) {
    var paramDesc = parameterType(i).describeConstable();
    if (paramDesc.isEmpty())
        return Optional.empty();
    params[i] = paramDesc.get();
}
return Optional.of(MethodTypeDesc.of(returnType().get(), params));


To avoid creating exceptions and allocating array when the params array is 
empty.

src/java.base/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java 
line 162:

> 160:         } else {
> 161:             Class<?> src;
> 162:             if (arg == functional || functional.isPrimitive()) {

`arg == functional` avoids a cast, though it's not in parity with the older 
code. Should probably restore the old cast that takes a source argument to 
avoid adding `==` checks to avoid casts.

src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java 
line 379:

> 377:     @Override
> 378:     public ClassEntry classEntry(ClassDesc classDesc) {
> 379:         if (classDesc == ConstantDescs.CD_Object) {

What causes the slow lookup of Object CE? If it's because that hashing needs to 
compute the substring first, I recommend changing the hashing algorithm if 
that's the case.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428838012
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428838938
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428845878
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428856469
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428851052
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428853927
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428854077
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428854309
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428855265
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428850744
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428857603
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428859242
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428860067
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428862861
PR Review Comment: https://git.openjdk.org/jdk/pull/17108#discussion_r1428863415

Reply via email to