[
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)