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 * A value, that is the result of an operation or a block parameter.
32 *
33 * @sealedGraph
34 */
35 public sealed abstract class Value implements CodeItem
36 permits Block.Parameter, Op.Result {
37 final Block block;
38 final CodeType type;
39 // @@@ In topological order?
40 // Can the representation be more efficient e.g. an array?
41 final SequencedSet<Op.Result> uses;
42
43 Value(Block block, CodeType type) {
44 this.block = block;
45 this.type = type;
46 this.uses = new LinkedHashSet<>();
47 }
48
49 /**
50 * Returns this value's declaring block.
51 * <p>If the value is an operation result, then the declaring block is the operation's parent block.
52 * If the value is a block parameter then the declaring block is the block declaring the parameter.
53 *
54 * @return the value's declaring block.
55 * @throws IllegalStateException if the declaring block is
56 * <a href="Body.Builder.html#body-building-observability">unobservable</a>
57 */
58 public Block declaringBlock() {
59 if (!isBuilt()) {
60 throw new IllegalStateException("Declaring block is unobservable");
61 }
62 return block;
63 }
64
65 /**
66 * Returns this value's declaring code element.
67 * <p>If the value is an operation result, then the declaring code element is the operation.
68 * If the value is a block parameter then the declaring code element is this value's declaring block.
69 *
70 * @return the value's declaring code element.
71 * @throws IllegalStateException if the declaring code element is a block and that block is
72 * <a href="Body.Builder.html#body-building-observability">unobservable</a>
73 */
74 public CodeElement<?, ?> declaringElement() {
75 return switch (this) {
76 case Block.Parameter _ -> declaringBlock();
77 case Op.Result r -> r.op();
78 };
79 }
80
81 /**
82 * Returns the type of the value.
83 *
84 * @return the type of the value.
85 */
86 public CodeType type() {
87 return type;
88 }
89
90 /**
91 * Returns this value as an operation result.
92 * <p>
93 * This method is a narrowing conversion from {@code Value} to {@link Op.Result}.
94 * If this value is not an operation result, this method throws an exception.
95 *
96 * @return this value, as an operation result.
97 * @throws IllegalStateException if this value is not an operation result.
98 * @see #queryResult()
99 * @see Op.Result
100 */
101 public Op.Result asResult() {
102 if (this instanceof Op.Result r) {
103 return r;
104 }
105 throw new IllegalStateException("Value is not an operation result");
106 }
107
108 /**
109 * Queries this value as an operation result.
110 *
111 * @return an optional containing this value as an operation result, otherwise
112 * an empty optional if this value is not an operation result
113 * @see #asResult()
114 * @see Op.Result
115 */
116 public Optional<Op.Result> queryResult() {
117 return this instanceof Op.Result r
118 ? Optional.of(r)
119 : Optional.empty();
120 }
121
122 /**
123 * Returns this value as a block parameter.
124 * <p>
125 * This method is a narrowing conversion from {@code Value} to {@link Block.Parameter}.
126 * If this value is not a block parameter, this method throws an exception.
127 *
128 * @return this value, as a block parameter.
129 * @throws IllegalStateException if this value is not a block parameter.
130 * @see #queryParameter()
131 * @see Block.Parameter
132 */
133 public Block.Parameter asParameter() {
134 if (this instanceof Block.Parameter p) {
135 return p;
136 }
137 throw new IllegalStateException("Value is not a block parameter");
138 }
139
140 /**
141 * Queries this value as a block parameter.
142 *
143 * @return an optional containing this value as a block parameter, otherwise
144 * an empty optional if this value is not a block parameter
145 * @see #asParameter()
146 * @see Block.Parameter
147 */
148 public Optional<Block.Parameter> queryParameter() {
149 return this instanceof Block.Parameter p
150 ? Optional.of(p)
151 : Optional.empty();
152 }
153
154 /**
155 * Returns the values this value directly depends on.
156 * <p>
157 * An operation result depends on the set of values whose members are the operation's operands and block arguments
158 * of the operation's successors.
159 * A block parameter does not depend on any values, and therefore this method returns an empty sequenced set.
160 *
161 * @return the values this value directly depends on, as an unmodifiable sequenced set. For an operation result the
162 * operation's operands will occur first and then block arguments of each successor.
163 */
164 public abstract SequencedSet<Value> dependsOn();
165
166 /**
167 * Returns the uses of this value, specifically each operation result of an operation where this value is used as
168 * an operand or as an argument of a block reference that is a successor.
169 *
170 * @return the uses of this value, as an unmodifiable sequenced set. The encouncter order is unspecified
171 * and determined by the order in which operations are built into blocks.
172 * @throws IllegalStateException if this value's declaring block is
173 * <a href="Body.Builder.html#body-building-observability">unobservable</a>
174 */
175 public SequencedSet<Op.Result> uses() {
176 if (!isBuilt()) {
177 throw new IllegalStateException("Declaring block is unobservable");
178 }
179
180 return Collections.unmodifiableSequencedSet(uses);
181 }
182
183 /**
184 * Returns {@code true} if this value is dominated by the given value {@code dom}.
185 * <p>
186 * If this value and {@code dom} are declared in different blocks, then this method
187 * returns the result of testing whether this value's declaring block is
188 * {@link Block#isDominatedBy dominated by} {@code dom}'s declaring block.
189 * <p>
190 * Otherwise, if both values are declared in the same block then:
191 * <ul>
192 * <li>if {@code dom} is a block parameter, then this value is dominated by {@code dom}.
193 * <li>if this value is a block parameter, then this value is <b>not</b> dominated by {@code dom}.
194 * <li>otherwise, both values are operation results, then this value is dominated by
195 * {@code dom} if this value is the same as {@code dom} or this value's operation occurs
196 * after {@code dom}'s operation in the declaring block.
197 * </ul>
198 *
199 * @param dom the dominating value
200 * @return {@code true} if this value is dominated by the given value {@code dom}.
201 * @see Block#isDominatedBy
202 */
203 public boolean isDominatedBy(Value dom) {
204 if (this == dom) {
205 return true;
206 }
207
208 if (declaringBlock() != dom.declaringBlock()) {
209 return declaringBlock().isDominatedBy(dom.declaringBlock());
210 }
211
212 // Any value is dominated by a block parameter
213 if (dom instanceof Block.Parameter) {
214 return true;
215 } else if (this instanceof Block.Parameter) {
216 return false;
217 } else {
218 assert this instanceof Op.Result &&
219 dom instanceof Op.Result;
220 List<Op> ops = declaringBlock().ops();
221 return ops.indexOf(((Op.Result) this).op()) >= ops.indexOf(((Op.Result) dom).op());
222 }
223 }
224
225 /**
226 * Compares two values by comparing their declaring elements.
227 *
228 * @apiNote
229 * This method behaves is if it returns the result of the following expression but may be implemented more
230 * efficiently.
231 * {@snippet :
232 * Comparator.comparing(Value::declaringElement, CodeElement::compare).compare(a, b)
233 * }
234 * @param a the first value to compare
235 * @param b the second value to compare
236 * @return the value {@code 0} if {@code a == b}; {@code -1} if {@code a} is less than {@code b}; and {@code -1}
237 * if {@code a} is greater than {@code b}.
238 * @throws IllegalArgumentException if {@code a} and {@code b} are not present in the same code model
239 * @see CodeElement#compare
240 */
241 public static int compare(Value a, Value b) {
242 return CodeElement.compare(a.declaringElement(), b.declaringElement());
243 }
244
245 boolean isBuilt() {
246 return block.isBuilt();
247 }
248 }