Classfile API proposal to integrate basic print functionality directly to ClassModel and MethodModel
Brian Goetz
brian.goetz at oracle.com
Thu Jul 21 15:59:19 UTC 2022
You could — we have a buffering builder internally (not yet exposed) that just accumulates a List<Element>; this is something that we could press into service for exposing a debugging mode. (We don’t want to do this by default because it slows down the pipeline.). But, this is in the same category as “set the option to not generate stack maps” — it means that the user has to re-run the computation with different code, which is annoying for a compiler and super-duper-annoying when the transform is being done on the fly as part of a framework.
Alternately, since build() and friends take a Consumer<Builder>, the user can wrap that consumer with one that logs the elements somewhere. But again, that’s a manual intervention.
Another idea is to embrace the “re-run the lambda” approach that we do with optimizing branch offsets; if a CodeBuilder fails to verify, re-run the same lambda in a buffering builder to get more observability.
The ClassModelBuilder approach you suggest could be easily exposed, and I think it has value, but it has some rough edges — the buffering builders don’t implement all the functionality that the direct builders do (e.g., you can’t ask it “what’s the current BCI”). So while this is totally a valid thing to expose and would likely be useful and is easy to do, it’s not purely a drop-in replacement for building directly right now.
> For debugging, could you replace the builder with a dummy builder which would print the class instead of actually building a byte array? More generally could you insert a "no-op" class transform anywhere in a transformation chain, which would print the class instead of transforming it? This is how we do this in ASM, with the TraceClassVisitor (which can be used instead of ClassWriter, or anywhere in a chain of visitors). But maybe this is not possible/desirable with this API?
>
> Maybe a "ClassModelBuilder" (ClassModel build(ClassDesc thisClass, Consumer<ClassBuilder> handler)) could be useful too?
>
> Eric
>
>>> Is there a way to print out a trace of parts fed to CodeBuilder instances?
>>>
>>> Just this morning I had Classfile die on me because of a stack underflow,
>>> and it was quite hard to find out which parts were missing from the Code
>>> attribute. And that with a Code totalling just 5 instructions...
>>>
>>> If there would have been bytes output, then I could have inspected the
>>> situation with javap. But if I mess up and pass inconsistent data to
>>> CodeBuilder, causing it to throw instead of producing a byte array, then
>>> I have an observability gap.
>>>
>>> -- mva
>>>
More information about the classfile-api-dev
mailing list