Classfile API Synchronous Stack Tracking in CodeBuilder

Paul Sandoz paul.sandoz at oracle.com
Fri Aug 26 21:11:34 UTC 2022


Me too, I was wondering if this functionality could be separated out and composed.

Paul.

> On Aug 26, 2022, at 7:12 AM, Brian Goetz <brian.goetz at oracle.com> wrote:
> 
> 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 the transform to apply to the code generated by the handler
>> * @param handler handler that receives a {@linkplain BlockCodeBuilder} to
>> * generate the code.
>> * @return this builder
>> */
>> default CodeBuilder transforming(CodeTransform transform, Consumer<CodeBuilder> handler) {
>>     var resolved = transform.resolve(this);
>>     resolved.startHandler().run();
>>     handler.accept(new TransformingCodeBuilder(this, resolved.consumer()));
>>     resolved.endHandler().run();
>>     return this;
>> }
>>  
>> 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 -> {
>>         var stackTracker = new StackTracker();
>>         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



More information about the classfile-api-dev mailing list