1 package jdk.incubator.code.extern;
2
3 import jdk.incubator.code.*;
4
5 import java.util.List;
6 import java.util.Map;
7 import java.util.function.Function;
8
9 /**
10 * An operation's externalized state (a record) that can be utilized to construct an instance
11 * of an {@link Op} associated with that state, such as the operation's name.
12 *
13 * @param name the operation name
14 * @param location the source location associated with the operation, may be null
15 * @param operands the list of operands
16 * @param successors the list of successors
17 * @param resultType the operation result type
18 * @param attributes the operation's specific state as a map of attributes
19 * @param bodyDefinitions the list of body builders for building the operation's bodies
20 * @apiNote Deserializers of operations may utilize this record to construct operations,
21 * thereby separating the specifics of deserializing from construction.
22 */
23 public record ExternalizedOp(String name,
24 Op.Location location,
25 List<Value> operands,
26 List<Block.Reference> successors,
27 TypeElement resultType,
28 Map<String, Object> attributes,
29 List<Body.Builder> bodyDefinitions) {
30
31 /**
32 * The attribute value that represents the external null value.
33 */
34 public static final Object NULL_ATTRIBUTE_VALUE = new Object();
35
36 /**
37 * Constructs a new externalized operation
38 * @param name the operation name
39 * @param location the source location associated with the operation, may be null
40 * @param operands the list of operands
41 * @param successors the list of successors
42 * @param resultType the operation result type
43 * @param attributes the operation's specific state as a map of attributes
44 * @param bodyDefinitions the list of body builders for building the operation's bodies
45 */
46 public ExternalizedOp {
47 attributes = Map.copyOf(attributes);
48 }
49
50 /**
51 * Gets an attribute value from the attributes map, converts the value by applying it
52 * to mapping function, and returns the result.
53 *
54 * <p>If the attribute is a default attribute then this method first attempts to
55 * get the attribute whose name is the empty string, otherwise if there is no such
56 * attribute present or the attribute is not a default attribute then this method
57 * attempts to get the attribute with the given name.
58 *
59 * <p>On successfully obtaining the attribute its value is converted by applying the value
60 * to the mapping function. A {@code null} value is represented by the value
61 * {@link ExternalizedOp#NULL_ATTRIBUTE_VALUE}.
62 *
63 * <p>If no attribute is present the {@code null} value is applied to the mapping function.
64 *
65 * @param name the attribute name.
66 * @param isDefault true if the attribute is a default attribute
67 * @param mapper the function used to convert the attribute value
68 * @param <T> the converted attribute value type
69 * @return the converted attribute value
70 */
71 public <T> T extractAttributeValue(String name, boolean isDefault, Function<Object, T> mapper) {
72 Object value = null;
73 if (isDefault && attributes.containsKey("")) {
74 value = attributes.get("");
75 assert value != null;
76 }
77
78 if (value == null && attributes.containsKey(name)) {
79 value = attributes.get(name);
80 assert value != null;
81 }
82
83 return mapper.apply(value);
84 }
85
86 /**
87 * Externalizes an operation's content.
88 * <p>
89 * If the operation is an instanceof {@code ExternalizableOp} then the operation's
90 * specific content is externalized to an attribute map, otherwise the attribute map
91 * is empty.
92 *
93 * @param cc the code context
94 * @param op the operation
95 * @return the operation's content.
96 */
97 public static ExternalizedOp externalizeOp(CodeContext cc, Op op) {
98 return new ExternalizedOp(
99 op.externalizeOpName(),
100 op.location(),
101 cc.getValues(op.operands()),
102 op.successors().stream().map(cc::getSuccessorOrCreate).toList(),
103 op.resultType(),
104 op.externalize(),
105 op.bodies().stream().map(b -> b.copy(cc)).toList()
106 );
107 }
108 }