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 }