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 }