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