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

Gary D. Gregory commented on BCEL-378:
--------------------------------------

Hello [~iloveeclipse] 

Thank you for the report and your help with BCEL-377 

A PR would be greatly appreciated.

 

> 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