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 package jdk.incubator.code;
27
28 import java.util.*;
29
30 /**
31 * The abstract implementation of a non-terminating operation. All concrete non-terminating operations extend this
32 * class and implement {@link Op}.
33 *
34 * <h2>Operation implementation requirements</h2>
35 * <p>
36 * A concrete non-terminating operation class must satisfy the following requirements:
37 * <ul>
38 * <li>
39 * implement {@link #resultType()} to return the result type of operation instances;
40 * <li>
41 * implement {@link #transform(CodeContext, CodeTransformer)} to return a newly constructed, unplaced copy whose
42 * concrete class is the concrete operation class;
43 * <li>
44 * call an appropriate {@code AbstractOp} superclass constructor from each concrete operation constructor. Constructors
45 * for new operations pass the operation's operands to {@link #AbstractOp(List)}. Constructors for transformed copies
46 * can pass the input operation and code context to {@link #AbstractOp(AbstractOp, CodeContext)};
47 * <li>
48 * override {@link #bodies()} if instances may have bodies. If the operation class implements {@link Op.Nested}, then
49 * {@code bodies()} must return one or more bodies;
50 * <li>
51 * copy mutable constructor arguments that define successors, bodies, and operation-specific state, ensuring they are
52 * all fixed when construction completes; and
53 * <li>
54 * return unmodifiable views or immutable values from accessors that expose successors, bodies, and operation-specific
55 * state.
56 * </ul>
57 * <p>
58 * A concrete non-terminating operation class may additionally:
59 * <ul>
60 * <li>
61 * implement {@link jdk.incubator.code.extern.ExternalizedOp.Externalizable} to define an external form;
62 * <li>
63 * implement {@link Op.Lowerable} to define a lowering; and
64 * <li>
65 * provide operation-specific accessors for operation-specific state.
66 * </ul>
67 */
68 public non-sealed abstract class AbstractOp extends InternalAbstractOp {
69 /**
70 * Constructs a non-terminating operation with a list of operands.
71 *
72 * @param operands the list of operands, a copy of the list is performed if required.
73 * @throws IllegalArgumentException if an operand's declaring block is built.
74 */
75 protected AbstractOp(List<? extends Value> operands) {
76 super(operands);
77 }
78
79 /**
80 * Constructs a non-terminating with operands mapped from, and location copied from, the given operation.
81 * <p>
82 * The constructed operation's operands are the values mapped, in order, from the given operation's operands using
83 * the given code context. The constructed operation's location is the given operation's location, if any.
84 *
85 * @param that the operation
86 * @param cc the code context
87 * @throws IllegalArgumentException if an operation's operand has no context mapping
88 * @throws IllegalArgumentException if a mapped value's declaring block is built.
89 */
90 protected AbstractOp(AbstractOp that, CodeContext cc) {
91 super(that, cc);
92 }
93
94 /**
95 * {@inheritDoc}
96 * @implSpec this implementation returns an unmodifiable empty list.
97 */
98 @Override
99 public final List<Block.Reference> successors() {
100 return List.of();
101 }
102
103 /**
104 * The abstract implementation of a terminating operation. All concrete terminating operations extend this
105 * class and implement {@link Terminating}.
106 *
107 * <h2>Operation implementation requirements</h2>
108 * <p>
109 * A concrete terminating operation class must satisfy the implementation requirements of a concrete non-terminating
110 * operation specified by {@link AbstractOp} in addition to the following requirements:
111 * <ul>
112 * <li>
113 * override {@link #successors()} if instances may have successors;
114 * </ul>
115 * <p>
116 * A concrete terminating operation class may additionally:
117 * <ul>
118 * <li>
119 * implement {@link jdk.incubator.code.extern.ExternalizedOp.Externalizable} to define an external form;
120 * <li>
121 * implement {@link Lowerable} to define a lowering; and
122 * <li>
123 * provide operation-specific accessors for operation-specific state.
124 * </ul>
125 */
126 public non-sealed abstract static class Terminating extends InternalAbstractOp
127 implements Op.Terminating {
128
129 final List<Block.Reference> successors;
130
131 /**
132 * Constructs a terminating operation with a list of operands and list of successors
133 *
134 * @param operands the list of operands, a copy of the list is performed if required.
135 * @param successors the list of successors, a copy of the list is performed if required.
136 * @throws IllegalArgumentException if an operand's declaring block is built.
137 * @throws IllegalArgumentException if a successor's referencing block is built or successor's block argument's
138 * declaring block is built.
139 */
140 protected Terminating(List<? extends Value> operands, List<Block.Reference> successors) {
141 super(operands);
142
143 // @@@ Check unbuilt blocks/arguments
144 this.successors = List.copyOf(successors);
145 }
146
147 /**
148 * Constructs a terminating operation with a list of operands and an empty list of successors
149 *
150 * @param operands the list of operands, a copy of the list is performed if required.
151 * @throws IllegalArgumentException if an operand's declaring block is built.
152 */
153 protected Terminating(List<? extends Value> operands) {
154 this(operands, List.of());
155 }
156
157 /**
158 * Constructs a terminating operation with operands and successors mapped from, and location copied from, the given operation.
159 * <p>
160 * The constructed operation's operands are the values mapped, in order, from the given operation's operands using
161 * the given code context. The constructed operation's successors are the successors mapped, in order, from the
162 * given operation's successors using the given code context and applying
163 * {@link CodeContext#getReferenceOrCreate(Block.Reference)} to each successor. The constructed operation's location
164 * is the given operation's location, if any.
165 *
166 * @param that the operation
167 * @param cc the code context
168 * @throws IllegalArgumentException if an operation's operand has no context mapping
169 * @throws IllegalArgumentException if a mapped value's declaring block is built.
170 * @throws IllegalArgumentException if a mapped successor's referencing block is built or mapped successor's block
171 * argument's declaring block is built.
172 */
173 protected Terminating(AbstractOp.Terminating that, CodeContext cc) {
174 super(that, cc);
175
176 this.successors = that.successors().stream().map(s -> cc.getReferenceOrCreate(s)).toList();
177 }
178
179 @Override
180 public final List<Block.Reference> successors() {
181 return successors;
182 }
183 }
184 }