RFR: 8344942: Template-Based Testing Framework [v30]

Christian Hagedorn chagedorn at openjdk.org
Fri May 16 09:13:06 UTC 2025


On Fri, 16 May 2025 08:03:55 GMT, Emanuel Peter <epeter at openjdk.org> wrote:

>> **Goal**
>> We want to generate Java source code:
>> - Make it easy to generate variants of tests. E.g. for each offset, for each operator, for each type, etc.
>> - Enable the generation of domain specific fuzzers (e.g. random expressions and statements).
>> 
>> Note: with the Template Library draft I was already able to find a [list of bugs](https://bugs.openjdk.org/issues/?jql=labels%20%3D%20template-framework%20ORDER%20BY%20created%20DESC%2C%20summary%20DESC).
>> 
>> **How to get started**
>> When reviewing, please start by looking at:
>> https://github.com/openjdk/jdk/blob/d21a8aabaf3b191e851b6997c11bb30fcd0f942f/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestSimple.java#L60-L76
>> 
>> We have a Template with two arguments. They are typed (Integer and String). We then apply the arguments `template.withArgs(42, "7")`, producing a `TemplateWithArgs`. This can then be `render`ed to a String. And then that can be compiled and executed with the CompileFramework.
>> 
>> Second, look at this advanced test:
>> https://github.com/openjdk/jdk/blob/77079807042fc5a3af04e0ccccad4ecd89e21cdb/test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestAdvanced.java#L102-L119
>> 
>> And then for a "tutorial", look at:
>> `test/hotspot/jtreg/testlibrary_tests/template_framework/examples/TestTutorial.java`
>> 
>> It shows these features:
>> - The `body` of a Template is essentially a list of `Token`s that are concatenated.
>> - Templates can be nested: a `TemplateWithArgs` is also a `Token`.
>> - We can use `#name` replacements to directly format values into the String. If we had proper String Templates in Java, we would not need this feature.
>> - We can use `$var` to make variable names unique: if we applied the same template twice, we would get variable collisions. `$var` is then replaced with e.g. `var_7` in one template use and `var_42` in the other template use.
>> - The use of `Hook`s to insert code into outer (earlier) code locations. This is useful, for example, to insert fields on demand.
>> - The use of recursive templates, and `fuel` to limit the recursion.
>> - `Name`s: useful to register field and variable names in code scopes.
>> 
>> Next, look at the documentation in. This file is the heart of the Template Framework, and describes all the important features.
>> https://github.com/openjdk/jdk/blob/d21a8aabaf3b191e851b6997c11bb30fcd0f942f/test/hotspot/jtreg/compiler/lib/template_framework/Template.java#L31-L76
>> 
>> For a better experience, you may want...
>
> Emanuel Peter has updated the pull request incrementally with one additional commit since the last revision:
> 
>   apply offline suggestions by Christian

Some first comments for `Template`, will continue with the other files :-)

And thanks for bearing with us! I'm now also very happy about the naming and design. It was well worth to discuss the names and the design more in-depth. The result is very good now I think! :-)

test/hotspot/jtreg/compiler/lib/template_framework/Template.java line 229:

> 227: 
> 228:         /**
> 229:          * Renders the {@link Template} to {@link String}.

Suggestion:

         * Renders the {@link Template} to a {@link String}.

Could also be changed at the other `render()` methods.

test/hotspot/jtreg/compiler/lib/template_framework/Template.java line 410:

> 408:          */
> 409:         public String render(float fuel, A a, B b, C c) {
> 410:             return new TemplateToken.ThreeArgs(this, a, b, c).render(fuel);

Suggestion:

            return new TemplateToken.ThreeArgs<>(this, a, b, c).render(fuel);

test/hotspot/jtreg/compiler/lib/template_framework/Template.java line 413:

> 411:         }
> 412:     }
> 413: 

Suggestion:

test/hotspot/jtreg/compiler/lib/template_framework/Template.java line 612:

> 610: 
> 611:     /**
> 612:      * Default amount of fuel for Template rendering. It guides the nesting depth of Templates.

Maybe add here how to change:
Suggestion:

     * Default amount of fuel for Template rendering. It guides the nesting depth of Templates. Can be changed when
     * rendering a template with {@code render(fuel)} (e.g. {@link ZeroArgs#render(float)}).

test/hotspot/jtreg/compiler/lib/template_framework/Template.java line 618:

> 616:     /**
> 617:      * The default amount of fuel spent per Template. It is subtracted from the current {@link #fuel} at every
> 618:      * nesting level, and once the {@link #fuel} reaches zero, the nesting is supposed to terminate.

Same here:
Suggestion:

     * nesting level, and once the {@link #fuel} reaches zero, the nesting is supposed to terminate. Can be changed
     * with {@link #setFuelCost(float)} inside {@link #body(Object...)}.

test/hotspot/jtreg/compiler/lib/template_framework/Template.java line 620:

> 618:      * nesting level, and once the {@link #fuel} reaches zero, the nesting is supposed to terminate.
> 619:      */
> 620:     public final static float DEFAULT_FUEL_COST = 10.0f;

Suggestion:

    float DEFAULT_FUEL = 100.0f;

    /**
     * The default amount of fuel spent per Template. It is subtracted from the current {@link #fuel} at every
     * nesting level, and once the {@link #fuel} reaches zero, the nesting is supposed to terminate.
     */
    float DEFAULT_FUEL_COST = 10.0f;

test/hotspot/jtreg/compiler/lib/template_framework/Template.java line 631:

> 629:      * Example of a recursive Template, which checks the remaining {@link #fuel} at every level,
> 630:      * and terminates if it reaches zero. It also demonstrates the use of {@link TemplateBinding} for
> 631:      * the recursive use of Templates. We {@link Template.OneArgs#render} with {@code 30} total fuel, and spend {@code 5} fuel at each recursion level.

Long line can be split:
Suggestion:

     * the recursive use of Templates. We {@link Template.OneArgs#render} with {@code 30} total fuel, 
     * and spend {@code 5} fuel at each recursion level.
     * 
     * <p>

test/hotspot/jtreg/compiler/lib/template_framework/Template.java line 640:

> 638:      *     System.out.println("Currently at depth #depth with fuel #fuel");
> 639:      *     """,
> 640:      *     (fuel() > 0) ? binding.get().asToken(depth + 1)

Missing `:`:
Suggestion:

     *     (fuel() > 0) ? binding.get().asToken(depth + 1) :

test/hotspot/jtreg/compiler/lib/template_framework/Template.java line 675:

> 673:      * @return The token that performs the defining action.
> 674:      */
> 675:     static Token addName(Name name) {

I have not fully grasped the concept of these `Name`s, yet. The `generateWithNames()` example in `TestTutorial` is quite big and complex. Could you add there a simpler example to better understand this idea of names?

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

PR Review: https://git.openjdk.org/jdk/pull/24217#pullrequestreview-2845694798
PR Review Comment: https://git.openjdk.org/jdk/pull/24217#discussion_r2092554087
PR Review Comment: https://git.openjdk.org/jdk/pull/24217#discussion_r2092561787
PR Review Comment: https://git.openjdk.org/jdk/pull/24217#discussion_r2092562738
PR Review Comment: https://git.openjdk.org/jdk/pull/24217#discussion_r2092621482
PR Review Comment: https://git.openjdk.org/jdk/pull/24217#discussion_r2092625480
PR Review Comment: https://git.openjdk.org/jdk/pull/24217#discussion_r2092618666
PR Review Comment: https://git.openjdk.org/jdk/pull/24217#discussion_r2092637966
PR Review Comment: https://git.openjdk.org/jdk/pull/24217#discussion_r2092629499
PR Review Comment: https://git.openjdk.org/jdk/pull/24217#discussion_r2092658089


More information about the hotspot-compiler-dev mailing list