Classfile API Synchronous Stack Tracking in CodeBuilder

Brian Goetz brian.goetz at oracle.com
Fri Aug 26 14:12:50 UTC 2022


I like how this leans on the existing Transform abstraction -- and it is 
useful beyond just tracking -- it means existing transforms can be 
combined with generation if that is convenient.

If the user wants to chain some transforms together *and* wants to 
retain references to each element in the chain -- which they will 
probably want to do if there are multiple kinds of "trackers" here, such 
as tracking stack + tracking locals -- then there is a little trickiness 
to setting the pipeline up right.  The user will have to do something like:

     withMethodBody(b -> {
         StackTracker st = StackTracker.of();
         LocalTracker lt = LocalTracker.of();
         transforming(st.andThen(lt), cb -> { ... build here, can use 
st/lt ... });
     });

What's happening here is that the transforms are stateful, but the user 
is creating the transform instances directly, rather than through a 
factory, so they can retain references to them. This is totally OK, as 
long as the user doesn't try to reuse the same StackTracker instance 
across multiple methods at the same time.

The spec for StackTracker and friends will probably need some extensive 
examples to guide users to the right idiom.

On 8/26/2022 9:58 AM, Adam Sotona wrote:
>
> Based on various optiona how to expose the StackTracker through the 
> Classfile API I’ve decided to refactor the proposal in:
>
> https://github.com/openjdk/jdk-sandbox/pull/34
>
> Instead of embedded implementation and Classfile.Option here is a 
> proposal to expose StackTracker as CodeTransform and implement 
> CodeBuilder::transforming method:
>
> /**
>
> * 
> *Builds**code**fragment**generated**by**the**handler**and**synchronously**transformed.*
>
> * *@param*transform thetransformtoapplytothecodegeneratedbythehandler
>
> * *@param*handler handlerthatreceivesa {*@linkplain*BlockCodeBuilder} to
>
> * generatethecode.
>
> * *@return*thisbuilder
>
> */
>
> defaultCodeBuilder *transforming*(CodeTransform transform, 
> Consumer<CodeBuilder> handler) {
>
> varresolved = transform.resolve(this);
>
> resolved.startHandler().run();
>
>     handler.accept(newTransformingCodeBuilder(this, resolved.consumer()));
>
> resolved.endHandler().run();
>
> returnthis;
>
> }
>
> Modified usage of the StackTracker is reflected in the StackTrackerTest:
>
> Classfile./build/(ClassDesc./of/("Foo"), clb ->
>     clb.withMethodBody("m", 
> MethodTypeDesc./of/(ConstantDescs./CD_Void/), 0, cob -> {
> varstackTracker = newStackTracker();
>         cob.*transforming*(stackTracker, stcb -> {
> /assertEquals/(stackTracker.stack().get(), List./of/());
>             stcb.aload(0);
> /assertEquals/(stackTracker.stack().get(), List./of/(/ReferenceType/));
>             stcb.lconst_0();
> /assertEquals/(stackTracker.stack().get(), List./of/(/LongType/, 
> /ReferenceType/));
>             stcb.trying(tryb -> {
> /assertEquals/(stackTracker.stack().get(), List./of/(/LongType/, 
> /ReferenceType/));
>                 tryb.iconst_1();
> /assertEquals/(stackTracker.stack().get(), List./of/(/IntType/, 
> /LongType/, /ReferenceType/));
>                 tryb.ifThen(thb -> {
> /assertEquals/(stackTracker.stack().get(), List./of/(/LongType/, 
> /ReferenceType/));
>                     thb.constantInstruction(ClassDesc./of/("Phee"));
> /assertEquals/(stackTracker.stack().get(), List./of/(/ReferenceType/, 
> /LongType/, /ReferenceType/));
>                     thb.athrow();
> /assertFalse/(stackTracker.stack().isPresent());
>                 });
> /assertEquals/(stackTracker.stack().get(), List./of/(/LongType/, 
> /ReferenceType/));
>                 tryb.return_();
> /assertFalse/(stackTracker.stack().isPresent());
>             }, catchb -> catchb.catching(ClassDesc./of/("Phee"), cb -> {
> /assertEquals/(stackTracker.stack().get(), List./of/(/ReferenceType/));
>                 cb.athrow();
> /assertFalse/(stackTracker.stack().isPresent());
>             }));
>         });
> /assertTrue/(stackTracker.maxStackSize().isPresent());
> /assertEquals/((int)stackTracker.maxStackSize().get(), 4);
>     }));
>
> Thanks,
>
> Adam
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/classfile-api-dev/attachments/20220826/94305bc7/attachment-0001.htm>


More information about the classfile-api-dev mailing list