[ 
https://issues.apache.org/jira/browse/BCEL-378?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18029447#comment-18029447
 ] 

Andrey Loskutov commented on BCEL-378:
--------------------------------------

{quote}
A PR would be greatly appreciated.
{quote}
[~ggregory]: sorry, not from me. We don't use BCEL for writing bytecode in any 
of the project I'm involved with and beside this I'm just overloaded with other 
tasks that have higher prio.

> BCEL doesn't properly write lambdas
> -----------------------------------
>
>                 Key: BCEL-378
>                 URL: https://issues.apache.org/jira/browse/BCEL-378
>             Project: Commons BCEL
>          Issue Type: Bug
>          Components: Main
>    Affects Versions: 6.10.0
>            Reporter: Andrey Loskutov
>            Priority: Major
>         Attachments: javap_bcel.txt, javap_javac.txt
>
>
> Follow up on BCEL-377.
> It looks like BCEl is able to *read* but unable to *write* bytecode related 
> to lambdas.
> This is visible by disassembling class files generated by BCEL and javac for 
> https://github.com/apache/commons-bcel/blob/master/src/test/resources/Java8Example.java
>  as it is done by 
> https://github.com/apache/commons-bcel/blob/master/src/test/java/org/apache/bcel/util/BCELifierTest.java
> After Java 22, also javap reports errors on such classes.
> ASM would generate this code for the lambda in the Java8Example:
> {code}
> .filter((String s) -> s.length() > 2)
> {code}
> {code:title=ASMifier version}
> methodVisitor.visitInvokeDynamicInsn("test", 
> "()Ljava/util/function/Predicate;", new Handle(Opcodes.H_INVOKESTATIC, 
> "java/lang/invoke/LambdaMetafactory", "metafactory", 
> "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;",
>  false), new Object[]{Type.getType("(Ljava/lang/Object;)Z"), new 
> Handle(Opcodes.H_INVOKESTATIC, "Java8Example", "lambda$0", 
> "(Ljava/lang/String;)Z", true), Type.getType("(Ljava/lang/String;)Z")});
> {code}
> BCEL however seem to do way less for same instruction:
> {code:title=BCELifier version}
>  il.append(_factory.createInvoke("test", "test", new 
> ObjectType("java.util.function.Predicate"), Type.NO_ARGS, 
> Const.INVOKEDYNAMIC));
> {code}
> I believe org.apache.bcel.generic.INVOKEDYNAMIC is not properly implemented.
> I don't see anywhere references to "BootstrapMethods"
> https://stackoverflow.com/questions/30733557/what-is-a-bootstrap-method
> ASM does this:
> https://gitlab.ow2.org/asm/asm/-/blob/master/asm/src/main/java/org/objectweb/asm/MethodWriter.java?ref_type=heads#L1066-1092
> Note symbolTable.addConstantInvokeDynamic(name, descriptor, 
> bootstrapMethodHandle, bootstrapMethodArguments);
> This calls  addBootstrapMethod
> https://gitlab.ow2.org/asm/asm/-/blob/master/asm/src/main/java/org/objectweb/asm/SymbolTable.java?ref_type=heads#L946-L954
> I don't see anything comparable coming in BCEL. 
> I would expect code below doing something like adding bootstrap method 
> handles but I don't see it:
> * org.apache.bcel.util.BCELifier.visitJavaClass(JavaClass)
> * or org.apache.bcel.generic.ClassGen
> * or org.apache.bcel.generic.InstructionFactory.createInvoke(String, String, 
> Type, Type[], short, boolean)
> Here the javap output files produced by running *verbose* javap command on 
> javac generated class file and on BCEL generated class file.
> {code}
> /usr/lib/jvm/java-25/bin/javap -v -p -c -s -verify 
> /data/javac/Java8Example.class > /data/javac/javap_javac.txt
> /usr/lib/jvm/java-25/bin/javap -v -p -c -s -verify 
> /data/bcel/Java8Example.class > /data/bcel/javap_bcel.txt
> {code}
> Note "BootstrapMethods" entry added by javac and missing in BCEL version.
> Note also "InvokeDynamic #0" reference to the first bootstrap method in the 
> class:
> {code}
>   #70 = Utf8               BootstrapMethods
>   #71 = MethodType         #72            //  (Ljava/lang/Object;)Z
>   #72 = Utf8               (Ljava/lang/Object;)Z
>   #73 = MethodHandle       6:#74          // REF_invokeStatic 
> Java8Example.lambda$hello$0:(Ljava/lang/String;)Z
>   #74 = InterfaceMethodref #57.#75        // 
> Java8Example.lambda$hello$0:(Ljava/lang/String;)Z
>   #75 = NameAndType        #65:#66        // 
> lambda$hello$0:(Ljava/lang/String;)Z
>   #76 = MethodType         #66            //  (Ljava/lang/String;)Z
>   #77 = MethodHandle       6:#78          // REF_invokeStatic 
> java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
>   #78 = Methodref          #79.#80        // 
> java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
>   #79 = Class              #81            // 
> java/lang/invoke/LambdaMetafactory
>   #80 = NameAndType        #82:#83        // 
> metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
>   #81 = Utf8               java/lang/invoke/LambdaMetafactory
>   #82 = Utf8               metafactory
>   #83 = Utf8               
> (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
>   #84 = Utf8               InnerClasses
>   #85 = Class              #86            // 
> java/lang/invoke/MethodHandles$Lookup
>   #86 = Utf8               java/lang/invoke/MethodHandles$Lookup
>   #87 = Class              #88            // java/lang/invoke/MethodHandles
>   #88 = Utf8               java/lang/invoke/MethodHandles
>   #89 = Utf8               Lookup
> ...
> 36: invokedynamic #33,  0             // InvokeDynamic 
> #0:test:()Ljava/util/function/Predicate;
> ...
> BootstrapMethods:
>   0: #77 REF_invokeStatic 
> java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
>     Method arguments:
>       #71 (Ljava/lang/Object;)Z
>       #73 REF_invokeStatic Java8Example.lambda$hello$0:(Ljava/lang/String;)Z
>       #76 (Ljava/lang/String;)Z
> {code}
> These are abscent in BCEL version.
>  [^javap_bcel.txt]  [^javap_javac.txt] 
> I assume the problem was *always* there since introduction of INVOKEDYNAMIC 
> and just uncovered by the new javap implementation in Java 22+.
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to