Skip to content

Commit b41146c

Browse files
eme64chhagedorn
andcommitted
8367531: Template Framework: use scopes and tokens instead of misbehaving immediate-return-queries
Co-authored-by: Christian Hagedorn <[email protected]> Reviewed-by: rcastanedalo, mhaessig, chagedorn
1 parent 6fc8e49 commit b41146c

39 files changed

+3974
-1005
lines changed

test/hotspot/jtreg/compiler/arguments/TestMethodArguments.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public static Template.ZeroArgs generateTest(PrimitiveType type, int numberOfArg
6060
: IntStream.range(0, numberOfArguments)
6161
.mapToObj(i -> "x" + i)
6262
.collect(Collectors.joining(" + "));
63-
return Template.make(() -> Template.body(
63+
return Template.make(() -> Template.scope(
6464
Template.let("type", type.name()),
6565
Template.let("boxedType", type.boxedTypeName()),
6666
Template.let("arguments", arguments),
@@ -115,7 +115,7 @@ public static String generate(CompileFramework comp) {
115115
tests.add(generateTest(CodeGenerationDataNameType.longs(), i / 2).asToken());
116116
tests.add(generateTest(CodeGenerationDataNameType.doubles(), i / 2).asToken());
117117
}
118-
return Template.make(() -> Template.body(
118+
return Template.make(() -> Template.scope(
119119
Template.let("classpath", comp.getEscapedClassPathOfCompiledClasses()),
120120
"""
121121
import java.util.Arrays;

test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
import compiler.lib.compile_framework.*;
4646
import compiler.lib.template_framework.Template;
4747
import compiler.lib.template_framework.TemplateToken;
48-
import static compiler.lib.template_framework.Template.body;
48+
import static compiler.lib.template_framework.Template.scope;
4949
import static compiler.lib.template_framework.Template.let;
5050
import static compiler.lib.template_framework.Template.$;
5151
import compiler.lib.template_framework.library.CodeGenerationDataNameType;
@@ -99,7 +99,7 @@ public static String generate(CompileFramework comp) {
9999

100100
// Create the body for the test. We use it twice: compiled and reference.
101101
// Execute the expression and catch expected Exceptions.
102-
var bodyTemplate = Template.make("expression", "arguments", "checksum", (Expression expression, List<Object> arguments, String checksum) -> body(
102+
var bodyTemplate = Template.make("expression", "arguments", "checksum", (Expression expression, List<Object> arguments, String checksum) -> scope(
103103
"""
104104
try {
105105
""",
@@ -167,14 +167,14 @@ public static String generate(CompileFramework comp) {
167167
default -> throw new RuntimeException("not handled: " + type.name());
168168
};
169169
StringPair cmp = cmps.get(RANDOM.nextInt(cmps.size()));
170-
return body(
170+
return scope(
171171
", ", cmp.s0(), type.con(), cmp.s1()
172172
);
173173
});
174174

175175
// Checksum method: returns not just the value, but also does some range / bit checks.
176176
// This gives us enhanced verification on the range / bits of the result type.
177-
var checksumTemplate = Template.make("expression", "checksum", (Expression expression, String checksum) -> body(
177+
var checksumTemplate = Template.make("expression", "checksum", (Expression expression, String checksum) -> scope(
178178
let("returnType", expression.returnType),
179179
"""
180180
@ForceInline
@@ -201,7 +201,7 @@ public static String generate(CompileFramework comp) {
201201

202202
// We need to prepare some random values to pass into the test method. We generate the values
203203
// once, and pass the same values into both the compiled and reference method.
204-
var valueTemplate = Template.make("name", "type", (String name, CodeGenerationDataNameType type) -> body(
204+
var valueTemplate = Template.make("name", "type", (String name, CodeGenerationDataNameType type) -> scope(
205205
"#type #name = ",
206206
(type instanceof PrimitiveType pt) ? pt.callLibraryRNG() : type.con(),
207207
";\n"
@@ -213,7 +213,7 @@ public static String generate(CompileFramework comp) {
213213
//
214214
// To ensure that both the compiled and reference method use the same constraint, we put
215215
// the computation in a ForceInline method.
216-
var constrainArgumentMethodTemplate = Template.make("name", "type", (String name, CodeGenerationDataNameType type) -> body(
216+
var constrainArgumentMethodTemplate = Template.make("name", "type", (String name, CodeGenerationDataNameType type) -> scope(
217217
"""
218218
@ForceInline
219219
public static #type constrain_#name(#type v) {
@@ -247,7 +247,7 @@ public static String generate(CompileFramework comp) {
247247
"""
248248
));
249249

250-
var constrainArgumentTemplate = Template.make("name", (String name) -> body(
250+
var constrainArgumentTemplate = Template.make("name", (String name) -> scope(
251251
"""
252252
#name = constrain_#name(#name);
253253
"""
@@ -279,7 +279,7 @@ public static String generate(CompileFramework comp) {
279279
}
280280
}
281281
}
282-
return body(
282+
return scope(
283283
let("methodArguments",
284284
methodArguments.stream().map(ma -> ma.name).collect(Collectors.joining(", "))),
285285
let("methodArgumentsWithTypes",

test/hotspot/jtreg/compiler/lib/template_framework/AddNameToken.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,8 @@
2323

2424
package compiler.lib.template_framework;
2525

26+
/**
27+
* Represents the addition of the specified {@link Name} to the current scope,
28+
* or an outer scope if the inner scope is transparent to {@link Name}s.
29+
*/
2630
record AddNameToken(Name name) implements Token {}

test/hotspot/jtreg/compiler/lib/template_framework/CodeFrame.java

Lines changed: 94 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,96 @@
2929
import java.util.List;
3030

3131
/**
32-
* The {@link CodeFrame} represents a frame (i.e. scope) of code, appending {@link Code} to the {@code 'codeList'}
32+
* The {@link CodeFrame} represents a frame (i.e. scope) of generated code by appending {@link Code} to the {@link #codeList}
3333
* as {@link Token}s are rendered, and adding names to the {@link NameSet}s with {@link Template#addStructuralName}/
34-
* {@link Template#addDataName}. {@link Hook}s can be added to a frame, which allows code to be inserted at that
35-
* location later. When a {@link Hook} is {@link Hook#anchor}ed, it separates the Template into an outer and inner
36-
* {@link CodeFrame}, ensuring that names that are added inside the inner frame are only available inside that frame.
34+
* {@link Template#addDataName}. {@link Hook}s can be added to a code frame, which allows code to be inserted at that
35+
* location later.
3736
*
3837
* <p>
39-
* On the other hand, each {@link TemplateFrame} represents the frame (or scope) of exactly one use of a
40-
* Template.
38+
* The {@link CodeFrame} thus implements the {@link Name} non-transparency aspect of {@link ScopeToken}.
4139
*
4240
* <p>
43-
* For simple Template nesting, the {@link CodeFrame}s and {@link TemplateFrame}s overlap exactly.
44-
* However, when using {@link Hook#insert}, we simply nest {@link TemplateFrame}s, going further "in",
45-
* but we jump to an outer {@link CodeFrame}, ensuring that we insert {@link Code} at the outer frame,
46-
* and operating on the names of the outer frame. Once the {@link Hook#insert}ion is complete, we jump
47-
* back to the caller {@link TemplateFrame} and {@link CodeFrame}.
41+
* The {@link CodeFrame}s are nested relative to the order of the final rendered code. This can
42+
* diverge from the nesting order of the {@link Template} when using {@link Hook#insert}, where
43+
* the execution jumps from the current (caller) {@link CodeFrame} scope to the scope of the
44+
* {@link Hook#anchor}. This ensures that the {@link Name}s of the anchor scope are accessed,
45+
* and not the ones from the caller scope. Once the {@link Hook#insert}ion is complete, we
46+
* jump back to the caller {@link CodeFrame}.
47+
*
48+
* <p>
49+
* Note, that {@link CodeFrame}s and {@link TemplateFrame}s often go together. But they do diverge when
50+
* we call {@link Hook#insert}. On the {@link CodeFrame} side, the inserted scope is nested in the anchoring
51+
* scope, so that the inserted scope has access to the Names of the anchoring scope, and not the caller
52+
* scope. But the {@link TemplateFrame} of the inserted scope is nested in the caller scope, so
53+
* that the inserted scope has access to hashtag replacements of the caller scope, and not the
54+
* anchoring scope.
55+
*/
56+
57+
/*
58+
* Below, we look at an example, and show the use of CodeFrames (c) and TemplateFrames (t).
59+
*
60+
* Explanations:
61+
* - Generally, every scope has a CodeFrame and a TemplateFrame. There can be multiple
62+
* scopes inside a Template, and so there can be multiple CodeFrames and TemplateFrames.
63+
* In the drawing below, we draw the frames vertically, and give each a unique id.
64+
* - When we nest scopes inside scopes, we create a new CodeFrame and a new TemplateFrame,
65+
* and so they grow the same nested structure. Example: t3 is nested inside t2 and
66+
* c3 is nested inside c2b.
67+
* - The exception to this:
68+
* - At a hook.anchor, there are two CodeFrames. The first one (e.g. c2a) we call the
69+
* hook CodeFrame, it is kept empty until we insert code to the hook. The second
70+
* (e.g. c2b) we call the inner CodeFrame of the anchoring, into which we keep
71+
* generating the code that is inside the scope of the hook.anchor.
72+
* - At a hook.insert, the TemplateFrame (e.g. t4) is nested into the caller (e.g. t3),
73+
* while the CodeFrame (e.g. c4) is nested into the anchoring CodeFrame (e.g. c2a).
74+
*
75+
* Template(
76+
* t1 c1
77+
* t1 c1
78+
* t1 c1 Anchoring Scope
79+
* t1 c1 hook.anchor(scope(
80+
* t1 c1 t2 c2a
81+
* t1 c1 t2 c2a <------ CodeFrame nesting--------+
82+
* t1 c1 t2 c2a with generated code |
83+
* t1 c1 t2 and Names |
84+
* t1 c1 t2 ^ |
85+
* t1 c1 t2 +- Two CodeFramees |
86+
* t1 c1 t2 v |
87+
* t1 c1 t2 |
88+
* t1 c1 t2 c2b |
89+
* t1 c1 t2 c2b |
90+
* t1 c1 t2 c2b Caller Scope |
91+
* t1 c1 t2 c2b ... scope( |
92+
* t1 c1 t2 c2b ... t3 c3 | Insertion Scope
93+
* t1 c1 t2 c2b ... t3 c3 | hook.insert(transparentScope(
94+
* t1 c1 t2 c2b ... t3 c3 | t4 c4
95+
* t1 c1 t2 c2b ... t3 c3 +---- t4 ----c4
96+
* t1 c1 t2 c2b ... t3 c3 t4 c4
97+
* t1 c1 t2 c2b ... t3 c3 <-- TemplateFrame nesting ---t4 c4
98+
* t1 c1 t2 c2b ... t3 c3 with hashtag t4 c4 // t: Concerns Template Frame
99+
* t1 c1 t2 c2b ... t3 c3 and setFuelCost t4 c4 // c: Concerns Code Frame
100+
* t1 c1 t2 c2b ... t3 c3 t4 c4 "use hashtag #x" -> t: hashtag queried in Insertion (t4) and Caller Scope (t3)
101+
* t1 c1 t2 c2b ... t3 c3 t4 c4 c: code added to Anchoring Scope (c2a)
102+
* t1 c1 t2 c2b ... t3 c3 t4 c4
103+
* t1 c1 t2 c2b ... t3 c3 t4 c4 let("x", 42) -> t: hashtag definition escapes to Caller Scope (t3) because
104+
* t1 c1 t2 c2b ... t3 c3 t4 c4 Insertion Scope is transparent
105+
* t1 c1 t2 c2b ... t3 c3 t4 c4
106+
* t1 c1 t2 c2b ... t3 c3 t4 c4 dataNames(...)...sample() -> c: sample from Insertion (c4) and Anchoring Scope (c2a)
107+
* t1 c1 t2 c2b ... t3 c3 t4 c4 (CodeFrame nesting: c2a -> c4)
108+
* t1 c1 t2 c2b ... t3 c3 t4 c4 addDataName(...) -> c: names escape to the Caller Scope (c3) because
109+
* t1 c1 t2 c2b ... t3 c3 t4 c4 Insertion Scope is transparent
110+
* t1 c1 t2 c2b ... t3 c3 t4 c4
111+
* t1 c1 t2 c2b ... t3 c3 ))
112+
* t1 c1 t2 c2b ... t3 c3
113+
* t1 c1 t2 c2b ... t3 c3
114+
* t1 c1 t2 c2b ... )
115+
* t1 c1 t2 c2b
116+
* t1 c1 t2 c2b
117+
* t1 c1 ))
118+
* t1 c1
119+
* t1 c1
120+
* )
121+
*
48122
*/
49123
class CodeFrame {
50124
public final CodeFrame parent;
@@ -78,25 +152,16 @@ public static CodeFrame makeBase() {
78152
}
79153

80154
/**
81-
* Creates a normal frame, which has a {@link #parent} and which defines an inner
82-
* {@link NameSet}, for the names that are generated inside this frame. Once this
83-
* frame is exited, the name from inside this frame are not available anymore.
84-
*/
85-
public static CodeFrame make(CodeFrame parent) {
86-
return new CodeFrame(parent, false);
87-
}
88-
89-
/**
90-
* Creates a special frame, which has a {@link #parent} but uses the {@link NameSet}
91-
* from the parent frame, allowing {@link Template#addDataName}/
92-
* {@link Template#addStructuralName} to persist in the outer frame when the current frame
93-
* is exited. This is necessary for {@link Hook#insert}, where we would possibly want to
94-
* make field or variable definitions during the insertion that are not just local to the
95-
* insertion but affect the {@link CodeFrame} that we {@link Hook#anchor} earlier and are
96-
* now {@link Hook#insert}ing into.
155+
* Creates a normal frame, which has a {@link #parent}. It can either be
156+
* transparent for names, meaning that names are added and accessed to and
157+
* from an outer frame. Names that are added in a transparent frame are
158+
* still available in the outer frames, as far out as the next non-transparent
159+
* frame. If a frame is non-transparent, this frame defines an inner
160+
* {@link NameSet}, for the names that are generated inside this frame. Once
161+
* this frame is exited, the names from inside this frame are not available.
97162
*/
98-
public static CodeFrame makeTransparentForNames(CodeFrame parent) {
99-
return new CodeFrame(parent, true);
163+
public static CodeFrame make(CodeFrame parent, boolean isTransparentForNames) {
164+
return new CodeFrame(parent, isTransparentForNames);
100165
}
101166

102167
void addString(String s) {

0 commit comments

Comments
 (0)