1 /*
2 * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 /// Defines an enhancement to the [core reflection][java.lang.reflect] API called _code reflection_.
27 ///
28 /// Code reflection supports access to a model of code in a method or lambda expression, a
29 /// [_code model_](#code-models-heading), that is suited for analysis and [transformation](#transforming-heading).
30 ///
31 /// This package documentation is organized into three parts. The first part introduces code reflection using
32 /// examples and explains how code reflection extends the core reflection API. The second part builds on those examples
33 /// and explains how code models can be traversed, executed, built, and transformed. The third part more formally
34 /// explains code model structure, code model behavior, dialects, and the use of `core` and `Java` dialects to define
35 /// Java code models.
36 ///
37 /// ## Core reflection API
38 ///
39 /// The core reflection API is a powerful feature that enables inspection of Java code at run time. For example,
40 /// consider the following Java code that we want to inspect, a class containing one field and one method, and another
41 /// class also containing one field and one method.
42 ///
43 /// {@snippet lang = "java":
44 /// static class Example {
45 /// static Runnable R = () -> IO.println("Example:field:R");
46 /// static int add(int a, int b) {
47 /// IO.println("Example:method:add");
48 /// return a + b;
49 /// }
50 ///
51 /// static class Nested {
52 /// static Runnable R = () -> IO.println("Example.Nested:field:R");
53 /// void m() { IO.println("Example.Nested:method:m"); }
54 /// }
55 /// }
56 ///}
57 ///
58 /// We can write a simple stream that uses core reflection and traverses program structure, a tree of annotated
59 /// elements, starting from a given class and reporting elements in a topological order.
60 ///
61 /// {@snippet lang = "java":
62 /// static Stream<AnnotatedElement> elements(Class<?> c) {
63 /// return Stream.of(c).mapMulti((e, mapper) -> traverse(e, mapper));
64 /// }
65 /// private static void traverse(AnnotatedElement e,
66 /// Consumer<? super AnnotatedElement> mapper) {
67 /// mapper.accept(e);
68 /// if (e instanceof Class<?>c) {
69 /// for (Field df : c.getDeclaredFields()) { traverse(df, mapper); }
70 /// for (Method dm : c.getDeclaredMethods()) { traverse(dm, mapper); }
71 /// for (Class<?> dc : c.getDeclaredClasses()) { traverse(dc, mapper); }
72 /// }
73 /// }
74 ///}
75 ///
76 /// ([AnnotatedElement][java.lang.reflect.AnnotatedElement] is the common super type of [Class][java.lang.Class],
77 /// [Field][java.lang.reflect.Field], and [Method][java.lang.reflect.Method].)
78 ///
79 /// The `traverse` method recursively traverses a class's declared fields, methods, and enclosed class. Starting from
80 /// `Example`, using a class literal expression, we can print out the fields, methods, and classes we encounter.
81 ///
82 /// {@snippet lang = "java":
83 /// elements(Example.class)
84 /// .forEach(IO::println);
85 ///}
86 ///
87 /// More interestingly we can perform some simple analysis, such as counting the number of static fields whose type is
88 /// [Runnable][java.lang.Runnable].
89 ///
90 /// {@snippet lang = "java":
91 /// static boolean isStaticRunnableField(Field f) {
92 /// return f.accessFlags().contains(AccessFlag.STATIC)
93 /// && Runnable.class.isAssignableFrom(f.getType());
94 /// }
95 /// assert 2 == elements(Example.class)
96 /// .filter(e -> e instanceof Field f && isStaticRunnableField(f))
97 /// .count();
98 ///}
99 ///
100 /// However, it is not possible to perform some analysis of the code in the lambda expressions and methods. The core
101 /// reflection API can only inspect the classes, fields, and methods – it provides no facility to go deeper and inspect
102 /// code.
103 ///
104 /// ## Code reflection
105 ///
106 /// Using code reflection we can go deeper. We can update `Example` so that the code of the lambda expressions and
107 /// methods are accessible just like the fields and methods.
108 ///
109 /// {@snippet lang = "java":
110 /// import jdk.incubator.code.*;
111 /// import jdk.incubator.code.bytecode.*;
112 /// import jdk.incubator.code.dialect.core.*;
113 /// import jdk.incubator.code.dialect.java.*;
114 /// import static jdk.incubator.code.dialect.core.CoreOp.*;
115 /// import static jdk.incubator.code.dialect.java.JavaOp.*;
116 ///
117 /// static class Example {
118 /// @Reflect static Runnable R = () -> IO.println("Example:field:R"); // @link substring="@Reflect" target="Reflect"
119 /// @Reflect static int add(int a, int b) {
120 /// IO.println("Example:method:add");
121 /// return a + b;
122 /// }
123 ///
124 /// static class Nested {
125 /// @Reflect static Runnable R = () -> IO.println("Example.Nested:field:R");
126 /// @Reflect void m() { IO.println("Example.Nested:method:m"); }
127 /// }
128 /// }
129 /// }
130 ///
131 /// We declare the lambda expressions and methods to be reflectable by annotating their declarations with
132 /// [Reflect][jdk.incubator.code.Reflect]. By doing so we grant access to their code. When the source of the `Example`
133 /// class is compiled by javac it translates its internal model of method `add`’s code to a standard model, called a
134 /// [_code model_](#code-models-heading), and stores the code model in a class file related to the `Example` class file
135 /// where `add`’s code is compiled to bytecode. (The same occurs for the other method and lambda expressions.)
136 ///
137 /// A code model is an immutable tree of [_code elements_][jdk.incubator.code.CodeElement], where some kinds of code
138 /// element, called operations, model Java statements and expressions (for further details see the
139 /// [Code models](#code-models-heading) section).
140 ///
141 /// We can use code reflection to access the code model of an annotated element, which loads the corresponding code
142 /// model that was stored in the related class file.
143 ///
144 /// {@snippet lang = "java":
145 /// static Object getStaticFieldValue(Field f) {
146 /// try { return f.get(null); }
147 /// catch (IllegalAccessException e) { throw new RuntimeException(e); }
148 /// }
149 /// static Optional<? extends CodeElement<?, ?>> getCodeModel(AnnotatedElement ae) { // @link substring="CodeElement" target="CodeElement"
150 /// return switch (ae) {
151 /// case Method m -> Op.ofMethod(m); // @link substring="Op.ofMethod" target="Op#ofMethod"
152 /// case Field f when isStaticRunnableField(f) ->
153 /// Op.ofLambda(getStaticFieldValue(f)).map(Quoted::op); // @link substring="Op.ofLambda" target="Op#ofLambda"
154 /// default -> Optional.empty();
155 /// };
156 /// }
157 ///}
158 ///
159 /// The method `getCodeModel` returns the code model for a reflectable method or lambda expression, a code element that
160 /// is the root of the code model tree. By default, methods and lambda expressions are not reflectable, so we return an
161 /// optional value. If the annotated element is a method we retrieve the code model from the method. Otherwise, if the
162 /// annotated element is a static field whose type is `Runnable` we access its value, an instance of `Runnable` whose
163 /// result is produced from a lambda expression, and from that instance we retrieve the lambda expression’s code model.
164 /// The retrieval is slightly different for lambda expressions since they can capture values (for more details see the
165 /// [Declaring and accessing reflectable code](#declaring-and-accessing-reflectable-code-heading) section).
166 ///
167 /// We can use `getCodeModel` to map from `Example`’s annotated elements to their code models.
168 ///
169 /// {@snippet lang = "java":
170 /// elements(Example.class)
171 /// // AnnotatedElement -> CodeModel?
172 /// .flatMap(ae -> getCodeModel(ae).stream())
173 /// .forEach(IO::println);
174 ///}
175 ///
176 /// More interestingly we can now perform some simple analysis of code, such as extracting the values of the string
177 /// literal expressions that are printed.
178 ///
179 /// {@snippet lang = "java":
180 /// static final MethodRef PRINTLN = MethodRef.method(IO.class, "println", // @link substring="MethodRef" target="jdk.incubator.code.dialect.java.MethodRef"
181 /// void.class, Object.class);
182 /// static Optional<String> isPrintConstantString(CodeElement<?, ?> e) {
183 /// if (e instanceof InvokeOp i && // @link substring="InvokeOp" target="jdk.incubator.code.dialect.java.JavaOp.InvokeOp"
184 /// i.invokeDescriptor().equals(PRINTLN) &&
185 /// i.operands().get(0).declaringElement() instanceof ConstantOp cop && // @link substring="ConstantOp" target="jdk.incubator.code.dialect.core.CoreOp.ConstantOp"
186 /// cop.value() instanceof String s) {
187 /// return Optional.of(s);
188 /// } else {
189 /// return Optional.empty();
190 /// }
191 /// }
192 /// static List<String> analyzeCodeModel(CodeElement<?, ?> codeModel) {
193 /// return codeModel.elements()
194 /// // CodeElement -> String?
195 /// .flatMap(e -> isPrintConstantString(e).stream())
196 /// .toList();
197 /// }
198 ///}
199 ///
200 /// The method `analyzeCodeModel` uses a stream to [traverse](#traversing-heading) over all elements of a code model and
201 /// returns the list of string literal values passed to invocations of `IO.println`. We can then use `analyzeCodeModel`
202 /// to further refine our stream expression to print out all such string literal values.
203 ///
204 /// {@snippet lang = "java":
205 /// elements(Example.class)
206 /// // AnnotatedElement -> CodeModel?
207 /// .flatMap(ae -> getCodeModel(ae).stream())
208 /// // CodeModel -> List<String>
209 /// .map(codeModel -> analyzeCodeModel(codeModel))
210 /// .forEach(IO::println);
211 ///}
212 ///
213 /// ## <a id="declaring-and-accessing-reflectable-code-heading"/>Declaring and accessing reflectable code
214 ///
215 /// In total there are four syntactic locations where the [jdk.incubator.code.Reflect] annotation can appear, as
216 /// described in the [jdk.incubator.code.Reflect] documentation.
217 ///
218 /// The code model of a reflectable method is accessed by invoking [jdk.incubator.code.Op#ofMethod] with an argument
219 /// that is a `Method` instance (retrieved using the core reflection API) representing the reflectable method. The
220 /// result is an optional value that contains the code model modeling the method. For example, we can access the
221 /// code model for the `Example.add` method as follows:
222 ///
223 /// {@snippet lang = "java":
224 /// Method addMethod = Example.class.getDeclaredMethod("add", int.class, int.class);
225 /// CoreOp.FuncOp codeModel = Op.ofMethod(addMethod).orElseThrow(); // @link substring="CoreOp.FuncOp" target="jdk.incubator.code.dialect.core.CoreOp.FuncOp"
226 /// assert codeModel == Op.ofMethod(addMethod).orElseThrow();
227 ///}
228 ///
229 /// We assert that if we obtain the code model for a second time the _same_ instance is returned. The identity
230 /// of code elements (and more generally items) in the code model are stable, and therefore they can be used as
231 /// stable keys for associating code elements with other information.
232 ///
233 /// The code model of a reflectable lambda expression (or method reference) is accessed by invoking
234 /// [jdk.incubator.code.Op#ofLambda] with an argument that is an instance of a functional interface associated with the
235 /// reflectable lambda expression. The result is an optional value that contains a [jdk.incubator.code.Quoted] instance,
236 /// from which may be retrieved the code model modeling the lambda expression. In addition, it is possible to retrieve
237 /// a mapping from items in the code model that model final, or effectively final, variables used but
238 /// not declared in the lambda expression to their corresponding run time values. Such run time values are commonly
239 /// referred to as captured values. For example, we can access the code model for the lambda expression used to
240 /// initialize the `Example.R` field as follows:
241 ///
242 /// {@snippet lang = "java":
243 /// Field rField = Example.class.getDeclaredField("R");
244 /// Object rFieldInstance = rField.get(null);
245 /// Quoted<JavaOp.LambdaOp> quotedCodeModel = Op.ofLambda(rFieldInstance).orElseThrow(); // @link substring="Quoted" target="jdk.incubator.code.Quoted"
246 /// JavaOp.LambdaOp codeModel = quotedCodeModel.op(); // @link substring="JavaOp.LambdaOp" target="jdk.incubator.code.dialect.java.JavaOp.LambdaOp"
247 ///}
248 ///
249 /// If a lambda expression captures values we can additionally access those values. For example,
250 ///
251 /// {@snippet lang = "java":
252 /// int capture = 42;
253 /// @Reflect Runnable r = () -> IO.println(capture);
254 /// Quoted<JavaOp.LambdaOp> quotedCodeModel = Op.ofLambda(r).orElseThrow();
255 ///
256 /// SequencedMap<Value, Object> capturedValues = quotedCodeModel.capturedValues(); // @link substring="capturedValues()" target="jdk.incubator.code.Quoted#capturedValues"
257 /// assert capturedValues.size() == 1;
258 /// assert capturedValues.values().contains(42);
259 ///}
260 ///
261 /// ## <a id="code-models-heading"/>Code models
262 ///
263 ///
264 /// A code model is an _immutable_ instance of data structures that can, in general, model many kinds of code, be it
265 /// Java code or foreign code. It has some properties like an Abstract Syntax Tree ([AST][AST]) used by a source
266 /// compiler, such as modeling code as a tree of arbitrary depth, and some properties like an
267 /// [intermediate representation][IR] used by an optimizing compiler, such as modeling control flow and data flow as
268 /// graphs. These properties ensure code models can preserve many important details of code they model and ensure code
269 /// models are suited for analysis and transformation.
270 ///
271 /// [AST]: https://en.wikipedia.org/wiki/Abstract_syntax_tree
272 ///
273 /// [IR]: https://en.wikipedia.org/wiki/Intermediate_representation
274 ///
275 /// The primary data structure of a code model is a tree of [_code elements_][jdk.incubator.code.CodeElement]. There
276 /// are three kinds of code elements, [operation][jdk.incubator.code.Op], [body][jdk.incubator.code.Body], and
277 /// [block][jdk.incubator.code.Block]. The root of a code model is an operation, and descendant operations form a tree
278 /// of arbitrary depth.
279 ///
280 /// Code reflection supports representing the data structures of a code model, code elements for modeling Java language
281 /// constructs and behavior, traversing code models, building code models, and transforming code models.
282 ///
283 /// ## <a id="traversing-heading"/>Traversing
284 ///
285 /// A code model, a tree of code elements, can be traversed. One approach to write a recursive method that iterates
286 /// over code elements and their children. That way we can get a sense of what a code model contains.
287 ///
288 /// {@snippet lang = "java":
289 /// Method addMethod = Example.class.getDeclaredMethod("add", int.class, int.class);
290 /// CoreOp.FuncOp codeModel = Op.ofMethod(addMethod).orElseThrow();
291 ///
292 /// static void traverse(int depth, CodeElement<?, ?> e) {
293 /// IO.println(" ".repeat(depth) + e.getClass());
294 ///
295 /// for (CodeElement<?, ?> c : e.children()) { // @link substring="children()" target="jdk.incubator.code.CodeElement#children"
296 /// traverse(depth + 1, c);
297 /// }
298 /// }
299 /// traverse(0, codeModel);
300 ///}
301 ///
302 /// The `traverse` method prints out the class of the code element it encounters and prefixes that with white space
303 /// proportionate to the depth of the element in the code model tree. Invoking the `traverse` method with the code model
304 /// of the `Example.add` method prints out the following:
305 ///
306 /// {@snippet lang = "text":
307 /// class jdk.incubator.code.dialect.core.CoreOp$FuncOp
308 /// class jdk.incubator.code.Body
309 /// class jdk.incubator.code.Block
310 /// class jdk.incubator.code.dialect.core.CoreOp$VarOp
311 /// class jdk.incubator.code.dialect.core.CoreOp$VarOp
312 /// class jdk.incubator.code.dialect.core.CoreOp$ConstantOp
313 /// class jdk.incubator.code.dialect.java.JavaOp$InvokeOp
314 /// class jdk.incubator.code.dialect.core.CoreOp$VarAccessOp$VarLoadOp
315 /// class jdk.incubator.code.dialect.core.CoreOp$VarAccessOp$VarLoadOp
316 /// class jdk.incubator.code.dialect.java.JavaOp$AddOp
317 /// class jdk.incubator.code.dialect.core.CoreOp$ReturnOp
318 ///}
319 ///
320 /// We can observe that the top of the tree is the [FuncOp][jdk.incubator.code.dialect.core.CoreOp.FuncOp] which
321 /// contains one child, a [Body][jdk.incubator.code.Body], which in turn contains one child, a
322 /// [Block][jdk.incubator.code.Block], which in turn contains a sequence of eight operations. Bodies and blocks provide
323 /// additional structure for modeling code. Each operation models some part of the `add` methods code, for example
324 /// variable declaration operations (instances of [VarOp][jdk.incubator.code.dialect.core.CoreOp.VarOp]) model Java
325 /// variable declarations, in this case the method parameters, and the add operation (instance of
326 /// [AddOp][jdk.incubator.code.dialect.java.JavaOp.AddOp]) models the Java + operator.
327 ///
328 /// Alternatively, we can stream over elements of the code model (as we did previously when analyzing the code for
329 /// string literals) in the same topologically sorted order using the
330 /// [CodeElement.elements][jdk.incubator.code.CodeElement#elements] method.
331 ///
332 /// {@snippet lang = "java":
333 /// codeModel.elements().forEach((CodeElement<?, ?> e) -> {
334 /// int depth = 0;
335 /// var parent = e;
336 /// while ((parent = parent.parent()) != null) depth++; // @link substring="parent()" target="jdk.incubator.code.CodeElement#parent"
337 /// IO.println(" ".repeat(depth) + e.getClass());
338 /// });
339 ///}
340 ///
341 /// We compute the depth for each code element by traversing back up the code model tree until the root element is
342 /// reached. So, it is possible to traverse up and down the code model tree.
343 ///
344 /// A superior way to view the contents of a code model is to convert the root of the code model, an operation, to code
345 /// model text and print it out.
346 ///
347 /// {@snippet lang = "java":
348 /// IO.println(codeModel.toText()); // @link substring="toText()" target="jdk.incubator.code.Op#toText"
349 ///}
350 ///
351 /// The `toText` method will traverse the code elements in a similar manner as before but print out more detail.
352 ///
353 /// {@snippet lang = "text":
354 /// func @loc="22:5:file:///...Example.java" @"add" (
355 /// %0 : java.type:"int", %1 : java.type:"int")java.type:"int" -> {
356 /// %2 : Var<java.type:"int"> = var %0 @loc="22:5" @"a";
357 /// %3 : Var<java.type:"int"> = var %1 @loc="22:5" @"b";
358 /// %4 : java.type:"java.lang.String" = constant @loc="24:20" @"Example:method:add";
359 /// invoke %4 @loc="24:9" @java.ref:"java.lang.IO::println(java.lang.Object):void";
360 /// %5 : java.type:"int" = var.load %2 @loc="25:16";
361 /// %6 : java.type:"int" = var.load %3 @loc="25:20";
362 /// %7 : java.type:"int" = add %5 %6 @loc="25:16";
363 /// return %7 @loc="25:9";
364 /// };
365 ///}
366 ///
367 /// The format of code model’s text is unspecified. It is designed to be human-readable, and intended for debugging and
368 /// testing. It is also invaluable for explaining code models. To aid debugging each operation has line number
369 /// information, and the root operation also has source information from where the code model originated.
370 ///
371 /// The code model text shows the code model’s root element is a function declaration (`func`) operation. The
372 /// lambda-like expression represents the fusion of the function declaration operation’s single body and the body’s
373 /// first and only block, called the _entry_ block. Then there is a sequence of operations in the entry block. For each
374 /// operation there is an instance of a corresponding Java class, all of which extend from the abstract class
375 /// [Op][jdk.incubator.code.Op] and which have already seen when we printed out the operation classes. The printed
376 /// operations and printed operation classes occur in the same order since the `toText` method traverses the model in
377 /// the same order as we explicitly traversed.
378 ///
379 /// The entry block declares two values called [_block parameters_][jdk.incubator.code.Block.Parameter], `%0` and `%1`,
380 /// which model the method’s initial values for parameters `a` and `b`. The method parameter declarations are modeled as
381 /// embedded `var` operations, each initialized with a corresponding block parameter _used_ as the `var` operation’s
382 /// single _operand_. The `var` operations produce values called [_operation results_][jdk.incubator.code.Op.Result],
383 /// variable values `%2` and `%3`, which model the variables `a` and `b`. A variable value can be loaded from or stored
384 /// to using variable access operations, respectively modeling an expression that denotes a variable and assignment to a
385 /// variable. The expressions denoting parameters `a` and `b` are modeled as `var.load` operations that _use_ the
386 /// variable values `%2` and `%3` respectively as _operands_. The operation results of these operations are _used_ as
387 /// _operands_ of subsequent operations and so on, e.g., `%7` the result of the `add` operation modeling the `+`
388 /// operator is used as an operand of the `return` operation modeling the `return` statement.
389 ///
390 /// The source code of the `add` method might contain all sorts of syntactic details that `javac` rightly needs to know
391 /// about but are extraneous for modeling purposes. This complexity is not present in the code model. For example, the
392 /// same code model would be produced if the return statement’s expression was `((a) + (b))` instead of `a + b`.
393 ///
394 /// In addition to the code model containing code elements forming a tree it also contains other items called
395 /// [_code items_][jdk.incubator.code.CodeItem], [values][jdk.incubator.code.Value] (block parameters or operation
396 /// results) we previously introduced, that form bidirectional dependency graphs between their declaration and their
397 /// use. A value has a [_code type_][jdk.incubator.code.CodeType], another code item that classifies values.
398 /// In our example many of the code types model Java types, and some model the type of variable
399 /// values (the code type of the operation result of a var operation).
400 ///
401 /// Code models are in Static Single-Assignment ([SSA][SSA]) form, and there is no explicit distinction, as there is in
402 /// the source code, between Java [statements][java-statements] and [expressions][java-expressions]. Block parameters
403 /// and operation results are declared before they are used and cannot be reassigned (and we therefore require special
404 /// operations and code types to model variables as previously shown).
405 ///
406 /// [SSA]: https://en.wikipedia.org/wiki/Static_single-assignment_form
407 ///
408 /// [java-statements]: https://docs.oracle.com/javase/specs/jls/se25/html/jls-14.html
409 ///
410 /// [java-expressions]: https://docs.oracle.com/javase/specs/jls/se25/html/jls-15.html
411 ///
412 /// Finally, we can execute the code model by transforming it to bytecode, wrapping it in a method handle, and invoking
413 /// the handle.
414 ///
415 /// {@snippet lang = "java":
416 /// var handle = BytecodeGenerator.generate(MethodHandles.lookup(), codeModel); // @link substring="generate(" target="jdk.incubator.code.bytecode.BytecodeGenerator#generate"
417 /// assert Example.add(1, 1) == (int) handle.invokeExact(1, 1);
418 ///}
419 ///
420 /// ## Building
421 ///
422 /// Code reflection provides functionality to build code models. We can use the API to build an equivalent model of the
423 /// `Example.add` method we previously accessed and traversed.
424 ///
425 /// {@snippet lang = "java":
426 /// var builtCodeModel = func( // @link substring="func(" target="jdk.incubator.code.dialect.core.CoreOp#func"
427 /// "add",
428 /// CoreType.functionType(JavaType.INT, JavaType.INT, JavaType.INT))
429 /// .body((Block.Builder builder) -> { // @link substring="builder" target="jdk.incubator.code.Block.Builder"
430 /// // Check the entry block parameters
431 /// assert builder.parameters().size() == 2;
432 /// assert builder.parameters().stream().allMatch(
433 /// (Block.Parameter param) -> param.type().equals(JavaType.INT));
434 ///
435 /// // int a
436 /// VarOp varOpA = var("a", builder.parameters().get(0)); // @link substring="var(" target="jdk.incubator.code.dialect.core.CoreOp#var"
437 /// Op.Result varA = builder.op(varOpA); // @link substring="builder.op(" target="jdk.incubator.code.Block.Builder#op"
438 ///
439 /// // int b
440 /// VarOp varOpB = var("b", builder.parameters().get(1));
441 /// Op.Result varB = builder.op(varOpB);
442 ///
443 /// // IO.println("Example:method:add")
444 /// builder.op(invoke(PRINTLN, // // @link substring="invoke(" target="jdk.incubator.code.dialect.java.JavaOp#invoke"
445 /// builder.op(constant(JavaType.J_L_STRING, "Example:method:add"))));
446 ///
447 /// // return a + b;
448 /// builder.op(return_(
449 /// builder.op(add( // @link substring="add(" target="jdk.incubator.code.dialect.java.JavaOp#add"
450 /// builder.op(varLoad(varA)),
451 /// builder.op(varLoad(varB))))));
452 /// });
453 /// IO.println(builtCodeModel.toText());
454 ///}
455 ///
456 /// The consuming lambda expression passed to the `body` method operates on a
457 /// [block builder][jdk.incubator.code.Block.Builder], representing the
458 /// [entry block][jdk.incubator.code.Block#isEntryBlock()] being built. We use that to append operations to the entry
459 /// block. When an operation is appended it produces an operation result that can be _used_ as an _operand_ of a further
460 /// operation and so on. After consuming lambda expression completes the `body` method will then complete the
461 /// building of the returned operation, specifically building of entry [block][jdk.incubator.code.Block] element and its
462 /// parent [body][jdk.incubator.code.Body] element.
463 ///
464 /// Building, like the text output, mirrors the source code structure. Building is carefully designed so that
465 /// structurally invalid models cannot be built, either because it is correct by construction or because an exception is
466 /// produced when given invalid input.
467 ///
468 /// We don’t anticipate most users will commonly build complete models of Java code, since it’s a rather verbose and
469 /// tedious process, although potentially less so than other approaches e.g., building bytecode, or method handle
470 /// combinators. `Javac` already knows how to build models. In fact, `javac` uses the same API to build models, and the
471 /// run time uses it to produce models that are accessed. Instead, we anticipate many users will build parts of models
472 /// when they transform them.
473 ///
474 /// ## <a id="transforming-heading"/> Transforming
475 ///
476 /// Code reflection supports the transformation of code models by combining traversing and building. A code model
477 /// transformation is represented by a function that takes an operation, encountered in the (input) model being
478 /// transformed, and a code model builder for the resulting transformed (output) model, and mediates how, if at all,
479 /// that operation is transformed into other code elements that are built. We were inspired by the functional
480 /// [transformation][cf-transformation] approach devised by the Class-File API and adapted that design to work on the
481 /// nested structure of code models that are immutable trees of code elements.
482 ///
483 /// [cf-transformation]: https://openjdk.org/jeps/484#Transforming-class-files
484 ///
485 /// We can write a simple code model transformer that transforms our method’s code model, replacing the operation
486 /// modeling the `+` operator with an invocation operation modeling an invocation expression to the method
487 /// `Integer.sum`.
488 ///
489 /// {@snippet lang = "java":
490 /// final MethodRef SUM = MethodRef.method(Integer.class, "sum", int.class,
491 /// int.class, int.class);
492 /// CodeTransformer addToMethodTransformer = CodeTransformer.opTransformer(( // @link substring="opTransformer(" target="jdk.incubator.code.CodeTransformer#opTransformer"
493 /// Function<Op, Op.Result> builder,
494 /// Op inputOp,
495 /// List<Value> outputOperands) -> {
496 /// switch (inputOp) {
497 /// // Replace a + b; with Integer.sum(a, b);
498 /// case AddOp _ -> builder.apply(invoke(SUM, outputOperands));
499 /// // Copy operation
500 /// default -> builder.apply(inputOp);
501 /// }
502 /// });
503 ///}
504 ///
505 /// The code transformation function, passed as lambda expression to
506 /// [CodeTransformer.opTransformer][jdk.incubator.code.CodeTransformer#opTransformer], accepts as parameters a block
507 /// builder function, `builder`, an operation encountered when traversing the input code model, `inputOp`, and a list of
508 /// values in the output model being built that are associated with input operation’s operands, `outputOperands`. We
509 /// must have previously encountered and transformed the input operations whose results are associated with those
510 /// values, since values can only be used after they have been declared.
511 ///
512 /// In the code transformer we switch over the input operation, and in this case we just match on `add` operation and
513 /// by default any other operation. In the latter case we apply the input operation to the builder function, which
514 /// creates a new output operation that is a copy of the input operation, appends the new operation to the block being
515 /// built, and associates the new operation’s result with the input operation’s result. When we match on an `add`
516 /// operation we replace it by building part of a code model, a method `invoke` operation to the `Integer.sum` method
517 /// constructed with the given output operands. The result of the output `invoke` operation is automatically associated
518 /// with the result of the input `add` operation.
519 ///
520 /// We can then transform the method’s code model by invoking the
521 /// [FuncOp.transform][jdk.incubator.code.dialect.core.CoreOp.FuncOp#transform] method and passing the code transformer
522 /// as an argument.
523 ///
524 /// {@snippet lang = "java":
525 /// FuncOp transformedCodeModel = codeModel.transform(addToMethodTransformer);
526 /// IO.println(transformedCodeModel.toText());
527 ///}
528 ///
529 /// The transformed code model is naturally very similar to the input code model.
530 ///
531 /// {@snippet lang = "text":
532 /// func @loc="22:5:file:///...Example.java" @"add" (
533 /// %0 : java.type:"int", %1 : java.type:"int")java.type:"int" -> {
534 /// %2 : Var<java.type:"int"> = var %0 @loc="22:5" @"a";
535 /// %3 : Var<java.type:"int"> = var %1 @loc="22:5" @"b";
536 /// %4 : java.type:"java.lang.String" = constant @loc="24:20" @"Example:method:add";
537 /// invoke %4 @loc="24:9" @java.ref:"java.lang.IO::println(java.lang.Object):void";
538 /// %5 : java.type:"int" = var.load %2 @loc="25:16";
539 /// %6 : java.type:"int" = var.load %3 @loc="25:20";
540 /// %7 : java.type:"int" = invoke %5 %6 @java.ref:"java.lang.Integer::sum(int, int):int";
541 /// return %7 @loc="25:9";
542 /// };
543 ///}
544 ///
545 /// We can observe the `add` operation has been replaced with the `invoke` operation. Also, by default, each operation
546 /// that was copied preserves line number information. The code transformation function can also be applied unmodified
547 /// to more complex code containing many `+` operators in arbitrarily nested positions.
548 ///
549 /// ### Transforming primitive
550 ///
551 /// The code transformation function previously shown is not a direct implementation of functional interface
552 /// [CodeTransformer][jdk.incubator.code.CodeTransformer]. Instead, we adapted from another functional interface, which
553 /// is easier to implement for simpler transformations on operations. Direct implementations of `CodeTransformer` are
554 /// more complex but are also capable of more complex transformations, such as building new blocks and retaining more
555 /// control over associating values in the input and output models.
556 ///
557 /// The simple code transformer previously shown can be implemented more directly as follows.
558 ///
559 /// {@snippet lang = "java":
560 /// CodeTransformer lowLevelAddToMethodTransformer = (
561 /// Block.Builder builder,
562 /// Op inputOp) -> {
563 /// switch (inputOp) {
564 /// // Replace a + b; with Integer.sum(a, b);
565 /// case AddOp _ -> {
566 /// // Get output operands mapped to input op's operands
567 /// List<Value> outputOperands = builder.context().getValues(inputOp.operands());
568 ///
569 /// Op.Result r = builder.op(invoke(SUM, outputOperands));
570 ///
571 /// // Map input op's result to output result of invocation operation
572 /// builder.context().mapValue(inputOp.result(), r);
573 /// }
574 /// // Copy operation
575 /// default -> builder.op(inputOp);
576 /// }
577 /// // Return the block builder to continue building from for next operation
578 /// return builder;
579 /// };
580 ///}
581 ///
582 /// Here we directly use a [block builder][jdk.incubator.code.Block.Builder]. In the prior example the block builder
583 /// was hidden behind an implementation of the functional interface `Function<Op, Op.Result>` that manages the mapping
584 /// of the input operation's result to the output operation's result.
585 ///
586 /// Code reflection provides complex code transformers, such as those for
587 /// - progressively [lowering][jdk.incubator.code.CodeTransformer#LOWERING_TRANSFORMER] code models;
588 /// - [transforming][jdk.incubator.code.dialect.core.SSA] models into pure SSA-form (where variable related operations
589 /// are removed);
590 /// - [inlining][jdk.incubator.code.dialect.core.Inliner] models into other models; and
591 /// - [normalizing][jdk.incubator.code.dialect.core.NormalizeBlocksTransformer] to remove redundant blocks
592 ///
593 /// Crucially, all of the above code transformers (except for inlining) preserve the program behavior of the input code
594 /// model. However, in general, code transformers are not required to preserve program behavior and some will
595 /// intentionally not do so as they may transform into a different output programming domain that partially maps from
596 /// the input programming domain.
597 ///
598 /// ## Code model structure
599 ///
600 /// The primary data structure of a code model is a tree of [code elements][jdk.incubator.code.CodeElement]. There are
601 /// three kinds of code elements, [operation][jdk.incubator.code.Op], [body][jdk.incubator.code.Body], and
602 /// [block][jdk.incubator.code.Block]. An operation contains a [sequence][jdk.incubator.code.Op#bodies()] of zero or
603 /// more bodies. A body contains a [sequence][jdk.incubator.code.Body#blocks()] of one or more blocks. A block contains
604 /// a [sequence][jdk.incubator.code.Block#ops()] of one or more operations. The root of a code model is an operation,
605 /// and descendant operations form a tree of arbitrary depth.
606 ///
607 /// ### Bodies and blocks
608 ///
609 /// The first block in a body is called the [entry block][jdk.incubator.code.Block#isEntryBlock()]. The last operation
610 /// in a block is called a [terminating operation][jdk.incubator.code.Op.Terminating]. A terminating operation describes
611 /// how control is passed from the operation’s [parent][jdk.incubator.code.Op#parent()] block to an ancestor operation,
612 /// or how control is passed from the operation’s parent block to one or more non-entry sibling blocks. In the latter
613 /// case the terminating operation declares a [sequence][jdk.incubator.code.Op#successors()] of one or more
614 /// [references][jdk.incubator.code.Block.Reference] to blocks called successors.
615 ///
616 /// Block references form a data structure that is a control flow graph, where blocks are nodes in the graph and
617 /// references are directed edges in the graph. Blocks in a body occur in the same order as that produced by
618 /// topological sorting the control flow graph in reverse post-order, where the entry block always occurs first (since
619 /// it cannot be referenced) and any unreferenced blocks occur last (in any order). This ensures blocks are by default
620 /// traversed in a program order.
621 ///
622 /// ### Block parameters, operation results, and values
623 ///
624 /// A block declares a [sequence][jdk.incubator.code.Block#parameters()] of zero or more
625 /// [block parameters][jdk.incubator.code.Block.Parameter], values. An operation declares an
626 /// [operation result][jdk.incubator.code.Op.Result], also a value. [Values][jdk.incubator.code.Value] are variables
627 /// assigned exactly once, so code models are in static single-assignment (SSA) form.
628 ///
629 /// A value has a [code type][jdk.incubator.code.CodeType], classifying the value.
630 ///
631 /// An operation uses zero or more values in a [sequence][jdk.incubator.code.Op#operands()] of operands and in a
632 /// [sequence][jdk.incubator.code.Block.Reference#arguments()] of block arguments of any block references (the
633 /// same value may be used more than once in both cases). A value can be used by an operation only after it has been
634 /// declared and only if the operation's result is
635 /// [dominated by][jdk.incubator.code.Value#isDominatedBy(jdk.incubator.code.Value)] the value.
636 ///
637 /// The [declaring block][jdk.incubator.code.Value#declaringBlock()] of a value that is a block parameter is the block
638 /// that declares the block parameter. The declaring block of a value that is an operation result is the parent block
639 /// of the operation result’s operation.
640 ///
641 /// Values form two data structures that are dependency graphs and use graphs. Given a value we can ask what values this
642 /// value [depends on][jdk.incubator.code.Value#dependsOn()], and so on, to form a dependency graph. Or inversely we can
643 /// ask what operation results [use][jdk.incubator.code.Value#uses()] this value in their operations' operands and
644 /// successors (or what values depend on this value), and so on, to form a use graph.
645 ///
646 /// ## Code model behavior
647 ///
648 /// A code model's program behavior is described by the arrangement of operations, bodies, and blocks. This
649 /// arrangement has generic program behavior common to all code models and specific program behavior of a code model,
650 /// giving rise to program meaning, as specified each operation's modeling of program behavior and the arrangement of
651 /// the operations within in a code model.
652 ///
653 /// ### Environment and effects
654 ///
655 /// We can describe the generic program behavior in terms of an environment where code elements are executed. Execution
656 /// of a code element produces an effect that is used to update the environment and pass control to another code
657 /// element.
658 ///
659 /// There are three kinds of effect:
660 ///
661 /// 1. An operation result effect, containing a run time value for the operation result
662 /// 2. A terminating operation effect, containing a terminating operation and run time values for the operation's
663 /// operands
664 /// 3. A successor block effect, containing the successor block and run time values for the block's arguments.
665 ///
666 /// Each effect also contains the environment that the effect takes place in. The environment can be updated to a new
667 /// environment by binding run time values to (symbolic) values. The environment can be used to access run time values
668 /// given (symbolic) values.
669 ///
670 /// ### Execution of operations
671 ///
672 /// Execution of a non-terminating operation either completes _normally_ or _abruptly_, according to its specification.
673 /// If an operation completes normally it produces an operation result effect. If an operation completes abruptly it
674 /// produces a terminating operation effect.
675 ///
676 /// Execution of a terminating operation may produce a successor effect or a terminating operation effect, according to
677 /// its specification, An operation that is an of instance of [jdk.incubator.code.Op.BlockTerminating] can produce a
678 /// successor effect. An operation that is an of instance of [jdk.incubator.code.Op.BodyTerminating] can produce a
679 /// terminating operation effect.
680 ///
681 /// If an operation has one or more bodies it may execute them according to its specification. The effect produced by
682 /// executing a body may be used to determine whether to select and execute another body and so on until execution of
683 /// the operation completes (normally or abruptly) and produces its own effect.
684 ///
685 /// ### Execution of bodies
686 ///
687 /// Execution of a body produces a terminating operation effect.
688 ///
689 /// Execution first proceeds by selecting the body's entry block for execution with given run time values as arguments
690 /// for the entry block's parameters.
691 ///
692 /// The current environment is updated by binding the selected block's parameters to the given run time values, then the
693 /// selected block is executed:
694 ///
695 /// - If execution produces a successor effect then the effect's successor block becomes the selected block, the
696 /// effect's run time values become the given run time values, and the effect's environment becomes the current
697 /// environment. Execution of the selected block then proceeds in the same manner as previously described.
698 ///
699 /// - If execution of the selected block produces a terminating operation effect then execution of the body completes
700 /// and it produces that effect (passing the effect to execution of the parent operation, which may result in execution
701 /// completing abruptly).
702 ///
703 /// ### Execution of blocks
704 ///
705 /// Execution of a block produces a successor effect or a terminating operation effect.
706 ///
707 /// Execution first proceeds by selecting the first operation in the block.
708 ///
709 /// If the selected operation is a non-terminating operation then the non-terminating operation is executed:
710 ///
711 /// - If execution of the operation produces an operation result effect then the next operation becomes the selected
712 /// operation, and the current environment is updated by binding the operation's result to the effect's run time value.
713 /// Execution of the selected operation then proceeds as previously described.
714 ///
715 /// - If execution of the operation produces a terminating operation effect then execution of the block completes and
716 /// it produces that effect (passing the effect to execution of the parent body, which in turn passes the effect to the
717 /// execution of the parent operation, and which may result in execution completing abruptly).
718 ///
719 /// If the selected operation is a terminating operation then the terminating operation is executed, producing an
720 /// effect, and execution of the block completes with that effect (passing the effect to execution of the parent body).
721 ///
722 /// ### Implementing code model behavior
723 ///
724 /// To enhance our understanding of code model behavior we can describe the environment, effects, and code element
725 /// execution using Java code. Such Java code can serve as the basis for a simple interpreter of code models.
726 ///
727 /// The environment can be represented as an interface.
728 ///
729 /// {@snippet lang = "java":
730 /// public interface Env {
731 /// Env bind(List<? extends Value> symbolicValues, List<Object> runtimeValues);
732 /// Env bind(Value symbolicValue, Object runtimeValue);
733 /// List<Object> valuesOf(List<? extends Value> symbolicValues);
734 /// Object valueOf(Value symbolicValue);
735 /// }
736 /// }
737 ///
738 /// The effects can be implemented as sealed interfaces and records.
739 ///
740 /// {@snippet lang = "java":
741 /// public sealed interface BlockEffect
742 /// permits SuccessorEffect, TerminatingOpEffect { }
743 /// public sealed interface OpEffect
744 /// permits OpResultEffect, TerminatingOpEffect { }
745 ///
746 /// public record SuccessorEffect(Block successor, List<Object> args, Env e)
747 /// implements BlockEffect { }
748 /// public record TerminatingOpEffect(Op terminatingOp, List<Object> operands, Env e)
749 /// implements BlockEffect, OpEffect { }
750 /// public record OpResultEffect(Object result, Env e)
751 /// implements OpEffect { }
752 /// }
753 ///
754 /// The execution of operations can be represented as abstract methods (since each operation specifies its own
755 /// behavior).
756 ///
757 /// {@snippet lang = "java":
758 /// public abstract OpEffect executeOp(Op op, Env e);
759 /// public abstract <O extends Op & Op.Terminating> BlockEffect executeTerminatingOp(O op, Env e);
760 /// }
761 ///
762 /// The execution of a body can be implemented as follows.
763 ///
764 /// {@snippet lang = "java":
765 /// public TerminatingOpEffect executeBody(Body body, List<Object> args, Env e) {
766 /// Block block = body.entryBlock();
767 /// while (true) {
768 /// // bind block parameters
769 /// e = e.bind(block.parameters(), args);
770 /// switch (executeBlock(block, e)) {
771 /// // pass control to sibling block
772 /// case SuccessorEffect eff -> {
773 /// block = eff.successor(); args = eff.args(); e = eff.e();
774 /// }
775 /// // pass control to parent operation
776 /// case TerminatingOpEffect eff -> { return eff; }
777 /// }
778 /// }
779 /// }
780 /// }
781 ///
782 /// The execution of a block can be implemented as follows:
783 ///
784 /// {@snippet lang = "java":
785 /// public BlockEffect executeBlock(Block block, Env e) {
786 /// var op = block.firstOp();
787 /// for (; !(op instanceof Op.Terminating); op = block.nextOp(op)) {
788 /// switch (executeOp(op, e)) {
789 /// // operation completed normally, pass control to next operation
790 /// case OpResultEffect eff -> e = e.bind(op.result(), eff.result);
791 /// // operation completed abruptly, pass control to parent body
792 /// case TerminatingOpEffect eff -> { return eff; }
793 /// }
794 /// }
795 ///
796 /// return executeTerminatingOp((Op & Op.Terminating) op, e);
797 /// }
798 /// }
799 ///
800 /// ## Dialects
801 ///
802 /// A dialect is a set of related operations and code types. When expressed in a code model they give the model
803 /// program meaning. Program meaning is an emergent property determined by generic code model behavior,
804 /// each operation's modeling behavior, and the operations arrangement in the code model.
805 ///
806 /// Code reflection defines two dialects, the [core][jdk.incubator.code.dialect.core] dialect, and the
807 /// [Java][jdk.incubator.code.dialect.java] dialect.
808 ///
809 /// The `core` dialect defines operations, and code types, whose modeling behavior is general and common across
810 /// programming language platforms. For example, it provides operations for modeling functions, variables, tuples,
811 /// declaring constants, block branching, and yielding a result from a body. In support of those operations it provides
812 /// code types to model function types, variable types, and tuple types. Such operations and code types can be
813 /// used to compatibly model Java program behavior, such as modeling Java method declarations, or the declaration of
814 /// Java variables and access to them. A core operation is one that extends from the class
815 /// [CoreOp][jdk.incubator.code.dialect.core.CoreOp]. A core code type is one that extends from the class
816 /// [CoreType][jdk.incubator.code.dialect.core.CoreType].
817 ///
818 /// The `Java` dialect defines operations, and code types, whose modeling behavior is specific to Java. The majority
819 /// of the Java operations directly model Java statements and expressions. The Java code types provide rich modeling
820 /// of Java types that are denotable in Java source, and also provide modeling of references to Java declarations that
821 /// are composed of Java types and names (fields, methods, and records). A Java operation is one that extends from the
822 /// class [JavaOp][jdk.incubator.code.dialect.java.JavaOp]. A Java code type is one that extends from the class
823 /// [JavaType][jdk.incubator.code.dialect.java.JavaType] or the class
824 /// [JavaRef][jdk.incubator.code.dialect.java.JavaRef].
825 ///
826 /// A `core` or `java` operation capable of modeling a Java expression implements
827 /// [JavaExpression][jdk.incubator.code.dialect.java.JavaOp.JavaExpression].
828 /// A `core` or `java` operation capable of modeling a Java statement implements
829 /// [JavaStatement][jdk.incubator.code.dialect.java.JavaOp.JavaStatement].
830 ///
831 /// Users may provide their own dialect to give program meaning for a particular domain by extending
832 /// [Op][jdk.incubator.code.Op] with specific operation implementations, and implementing
833 /// [CodeType][jdk.incubator.code.CodeType] with specific code type implementations.
834 ///
835 /// ## Java code models
836 ///
837 /// Java code models are code models produced by `javac`, stored in class files, and accessed at run time. Such models
838 /// preserve the program meaning of the Java source code they model. They consist of an arrangement of operations and
839 /// code types from the `core` dialect and the `java` dialect.
840 ///
841 /// A Java code model also preserves the nested structure of the Java source code it models. It is guaranteed that a
842 /// body only has one block. To achieve this the Java dialect provides Java operations for directly modeling all
843 /// statements, expressions, and patterns. When `javac` encounters an expression or statement to model it will select
844 /// the corresponding operation.
845 ///
846 /// For example, when `javac` encounters a basic `for` statement to model it will select the
847 /// [Java.ForOp][jdk.incubator.code.dialect.java.JavaOp.ForOp]. A `ForOp` operation has four bodies that
848 /// respectively model the initialization code, the boolean `Expression`, a `Statement`, and update code of the basic
849 /// `for` statement. The `ForOp` operation specifies how it executes its bodies in a manner compatible with the Java
850 /// language specification, including normal and abrupt completion.
851 ///
852 /// A `ForOp` is capable of transforming itself by replacing itself and its bodies with a control flow graph of
853 /// interconnected basic blocks in its grandparent body. This is termed
854 /// [lowering][jdk.incubator.code.CodeTransformer#LOWERING_TRANSFORMER]. Java program behavior is preserved but the
855 /// nested structure of the code is not. The resulting code model elements represent a simplified modeling of the `for`
856 /// statement that can be easier to analyze.
857 ///
858 /// Generally, any Java operation that implements [Op.Lowerable][jdk.incubator.code.Op.Lowerable] can lower itself,
859 /// replacing itself and its bodies with interconnected basic blocks. This includes the
860 /// [JavaOp.TryOp][jdk.incubator.code.dialect.java.JavaOp.TryOp] modeling `try` statements (including those with
861 /// `finally` blocks), and the [JavaOp.SwitchExpressionOp][jdk.incubator.code.dialect.java.JavaOp.SwitchExpressionOp]
862 /// modeling switch expressions (including those with case patterns).
863 ///
864 package jdk.incubator.code;