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 }