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 * <p>
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 being built and is not observable.
56 */
57 public Block declaringBlock() {
58 if (!isBuilt()) {
59 throw new IllegalStateException("Declaring block is being built and is not observable");
60 }
61 return block;
62 }
63
64 /**
65 * Returns this value's declaring code element.
66 * <p>If the value is an operation result, then the declaring code element is the operation.
67 * If the value is a block parameter then the declaring code element is this value's declaring block.
68 *
69 * @return the value's declaring code element.
70 * @throws IllegalStateException if this value is a block parameter and its declaring block is being built and is
71 * not observable.
72 */
73 public CodeElement<?, ?> declaringElement() {
74 return switch (this) {
75 case Block.Parameter _ -> block;
76 case Op.Result r -> r.op();
77 };
78 }
79
80 /**
81 * Returns the type of the value.
82 *
83 * @return the type of the value.
84 */
85 public CodeType type() {
86 return type;
87 }
88
89 /**
90 * Returns this value as an operation result.
91 *
92 * @return the value as an operation result.
93 * @throws IllegalStateException if the value is not an instance of an operation result.
94 */
95 public Op.Result result() {
96 if (this instanceof Op.Result r) {
97 return r;
98 }
99 throw new IllegalStateException("Value is not an instance of operation result");
100 }
101
102 /**
103 * Returns this value as a block parameter.
104 *
105 * @return the value as a block parameter.
106 * @throws IllegalStateException if the value is not an instance of a block parameter.
107 */
108 public Block.Parameter parameter() {
109 if (this instanceof Block.Parameter p) {
110 return p;
111 }
112 throw new IllegalStateException("Value is not an instance of block parameter");
113 }
114
115 /**
116 * Returns the values this value directly depends on.
117 * <p>
118 * An operation result depends on the set of values whose members are the operation's operands and block arguments
119 * of the operation's successors.
120 * A block parameter does not depend on any values, and therefore this method returns an empty sequenced set.
121 *
122 * @return the values this value directly depends on, as an unmodifiable sequenced set. For an operation result the
123 * operation's operands will occur first and then block arguments of each successor.
124 */
125 public abstract SequencedSet<Value> dependsOn();
126
127 /**
128 * Returns the uses of this value, specifically each operation result of an operation where this value is used as
129 * an operand or as an argument of a block reference that is a successor.
130 *
131 * @return the uses of this value, as an unmodifiable sequenced set. The encouncter order is unspecified
132 * and determined by the order in which operations are built into blocks.
133 * @throws IllegalStateException if this value's declaring block is being built and is not observable.
134 */
135 public SequencedSet<Op.Result> uses() {
136 if (!isBuilt()) {
137 throw new IllegalStateException("Declaring block is being built and is not observable");
138 }
139
140 return Collections.unmodifiableSequencedSet(uses);
141 }
142
143 /**
144 * Returns {@code true} if this value is dominated by the given value {@code dom}.
145 * <p>
146 * If this value and {@code dom} are declared in different blocks, then this method
147 * returns the result of testing whether this value's declaring block is
148 * {@link Block#isDominatedBy dominated by} {@code dom}'s declaring block.
149 * <p>
150 * Otherwise, if both values are declared in the same block then:
151 * <ul>
152 * <li>if {@code dom} is a block parameter, then this value is dominated by {@code dom}.
153 * <li>if this value is a block parameter, then this value is <b>not</b> dominated by {@code dom}.
154 * <li>otherwise, both values are operation results, then this value is dominated by
155 * {@code dom} if this value is the same as {@code dom} or this value's operation occurs
156 * after {@code dom}'s operation in the declaring block.
157 * </ul>
158 *
159 * @param dom the dominating value
160 * @return {@code true} if this value is dominated by the given value {@code dom}.
161 * @throws IllegalStateException if an encountered block is being built and is not observable.
162 * @see Block#isDominatedBy
163 */
164 public boolean isDominatedBy(Value dom) {
165 if (this == dom) {
166 return true;
167 }
168
169 if (declaringBlock() != dom.declaringBlock()) {
170 return declaringBlock().isDominatedBy(dom.declaringBlock());
171 }
172
173 // Any value is dominated by a block parameter
174 if (dom instanceof Block.Parameter) {
175 return true;
176 } else if (this instanceof Block.Parameter) {
177 return false;
178 } else {
179 assert this instanceof Op.Result &&
180 dom instanceof Op.Result;
181 List<Op> ops = declaringBlock().ops();
182 return ops.indexOf(((Op.Result) this).op()) >= ops.indexOf(((Op.Result) dom).op());
183 }
184 }
185
186 /**
187 * Compares two values by comparing their declaring elements.
188 *
189 * @apiNote
190 * This method behaves is if it returns the result of the following expression but may be implemented more
191 * efficiently.
192 * {@snippet :
193 * Comparator.comparing(Value::declaringElement, CodeElement::compare).compare(a, b)
194 * }
195 * @param a the first value to compare
196 * @param b the second value to compare
197 * @return the value {@code 0} if {@code a == b}; {@code -1} if {@code a} is less than {@code b}; and {@code -1}
198 * if {@code a} is greater than {@code b}.
199 * @throws IllegalArgumentException if {@code a} and {@code b} are not present in the same code model
200 * @throws IllegalStateException if an encountered block is being built and is not observable.
201 * @see CodeElement#compare
202 */
203 public static int compare(Value a, Value b) {
204 return CodeElement.compare(a.declaringElement(), b.declaringElement());
205 }
206
207 boolean isBuilt() {
208 return block.isBuilt();
209 }
210 }