RFR: 8367531: Template Framework: use scopes and tokens instead of misbehaving immediate-return-queries [v6]

Manuel Hässig mhaessig at openjdk.org
Mon Oct 20 11:49:17 UTC 2025


On Tue, 14 Oct 2025 16:38:33 GMT, Emanuel Peter <epeter at openjdk.org> wrote:

>> I got some feedback from users of the Template Framework, especially @galderz . And personally, I already was slightly unsatisfied by some of the issues described below, but did not expect it to be as bad as it is.
>> 
>> So I'm sorry, but I think we need to do a significant re-design. It is now still early enough, and only trivial changes are required for the "real" uses of the framework. Only the framework internal tests require significant changes.
>> 
>> Many thanks to @galderz for trying out the framework, and reporting the issues. And thanks to @chhagedorn for spending a few hours in an offline meeting discussing the issue.
>> 
>> **Major issue with Template Framework: lambda vs token order**
>> 
>> The template rendering involves some state, such as keeping track of hashtag replacements, names and fuel cost.
>> Some methods have side-effects (`addDataName`, `let`, ...) and others are simple queries (`sample`, ...).
>> Sadly, the first version of the template framework was not very consistent, and created tokens (deferred evaluation, during token evaluation) for some, and for others it queried the state and returned the result immediately (during lambda execution). One nasty consequence is that an immediately returning query can "float" above a state affecting token. For example, `addDataName` generated a token (so that we know if it is to be added for the template frame or a hook anchoring frame), but answered sampling queries immediately (because that means we can use the returned value immediately and make decisions based on it immediately, which is nice). Looking at the example below, this had the confusing result that `addDataName` only generates a token at first, then `sample` does not have that name available yet, and only later during token evaluation is the name actually added.
>> 
>> var testTemplate = Template.make(() -> body(
>>     ...
>>     addDataName("name", someType, MUTABLE),
>>     let("name", dataNames(MUTABLE).exactOf(someType).sample().name()),
>>     ...
>> ));
>> 
>> 
>> **Two possible solutions: all-in on lambda execution or all-in on tokens**
>> 
>> First, I thought I want to go all-in on lambda execution, and have everything have immediate effect and return results immediately. This would have the nice effect that the user feels like they are directly in control of the execution order. But I did not find a good way without exposing too many internals to the user, or getting rid of the nice "token lists" we currently have inside Templates (the...
>
> Emanuel Peter has updated the pull request incrementally with two additional commits since the last revision:
> 
>  - Merge branch 'JDK-8367531-fix-addDataName' of https://github.com/eme64/jdk into JDK-8367531-fix-addDataName
>  - improve tutorial for Manuel

Thank you for the improved descriptions. It helped a lot with my understanding.

I have a few more nits, but otherwise, this looks good.

test/hotspot/jtreg/compiler/lib/template_framework/CodeFrame.java line 90:

> 88:      * frame. If a frame is non-transparent, this frame defines an inner
> 89:      * {@link NameSet}, for the names that are generated inside this frame. Once
> 90:      * this frame is exited, the name from inside this frame are not available.

Suggestion:

     * Creates a normal frame, which has a {@link #parent}. It can either be
     * transparent for names, meaning that names are added and accessed to and
     * from an outer frame. Names that are added in a transparent frame are
     * still available in the outer frames, as far out as the next non-transparent
     * frame. If a frame is non-transparent, this frame defines an inner
     * {@link NameSet}, for the names that are generated inside this frame. Once
     * this frame is exited, the names from inside this frame are not available.

Typos

test/hotspot/jtreg/compiler/lib/template_framework/Renderer.java line 396:

> 394:                     addHashtagReplacement(lt.key(), lt.value());
> 395:                 });
> 396: 

Suggestion:


Nit: remove superfluous line

test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestTutorial.java line 593:

> 591:             )),
> 592:             Hooks.METHOD_HOOK.insert(scope(
> 593:                 let("value", 11),

Suggestion:


This is unused now.

test/hotspot/jtreg/testlibrary_tests/template_framework/tests/TestTemplate.java line 1248:

> 1246:             sample: x.
> 1247:             sample: z.
> 1248:             """;

Suggestion:

            // Outer scope DataName:
            addDataName("outerInt", myInt, MUTABLE),
            dataNames(MUTABLE).exactOf(myInt).sample((DataName dn) -> scope(
                let("name1", dn.name()),
                "sample: #name1.\n",
                // We can also see the outer DataName:
                dataNames(MUTABLE).exactOf(myInt).sampleAndLetAs("name2"),
                "sample: #name2.\n",
                // Local DataName:
                addDataName("innerLong", myLong, MUTABLE),
                dataNames(MUTABLE).exactOf(myLong).sampleAndLetAs("name3"),
                "sample: #name3.\n"
            )),
            // We can still see the outer scope DataName:
            dataNames(MUTABLE).exactOf(myInt).sampleAndLetAs("name4"),
            "sample: #name4.\n",
            // But we cannot see the DataNames that are local to the inner scope.
            // So here, we will always see "outerLong", and never "innerLong".
            addDataName("outerLong", myLong, MUTABLE),
            dataNames(MUTABLE).exactOf(myLong).sampleAndLetAs("name5"),
            "sample: #name5.\n"
        ));

        String code = template.render();
        String expected =
            """
            sample: outerInt.
            sample: outerInt.
            sample: innerLong.
            sample: outerInt.
            sample: outerLong.
            """;

These names make the test a little easier to understand.

-------------

Changes requested by mhaessig (Committer).

PR Review: https://git.openjdk.org/jdk/pull/27255#pullrequestreview-3350990372
PR Review Comment: https://git.openjdk.org/jdk/pull/27255#discussion_r2444200025
PR Review Comment: https://git.openjdk.org/jdk/pull/27255#discussion_r2444319448
PR Review Comment: https://git.openjdk.org/jdk/pull/27255#discussion_r2440494414
PR Review Comment: https://git.openjdk.org/jdk/pull/27255#discussion_r2444014306


More information about the hotspot-compiler-dev mailing list