1 /*
  2  * Copyright (c) 2025, 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 package jdk.incubator.code.extern;
 26 
 27 import jdk.incubator.code.*;
 28 
 29 import java.util.List;
 30 import java.util.Map;
 31 
 32 /**
 33  * An operation's externalized state (a record) that can be utilized to construct an instance
 34  * of an {@link Op} associated with that state, such as the operation's name.
 35  *
 36  * @param name            the operation name
 37  * @param location        the source location associated with the operation, may be null
 38  * @param operands        the list of operands
 39  * @param successors      the list of successors
 40  * @param resultType      the operation result type
 41  * @param attributes      the operation's specific state as a map of attributes
 42  * @param bodyDefinitions the list of body builders for building the operation's bodies
 43  * @apiNote Deserializers of operations may utilize this record to construct operations,
 44  * thereby separating the specifics of deserializing from construction.
 45  */
 46 public record ExternalizedOp(String name,
 47                              Op.Location location,
 48                              List<Value> operands,
 49                              List<Block.Reference> successors,
 50                              CodeType resultType,
 51                              Map<String, Object> attributes,
 52                              List<Body.Builder> bodyDefinitions) {
 53 
 54     /**
 55      * An operation characteristic indicating the operation's name and operation specific state is externalizable.
 56      */
 57     public interface Externalizable {
 58         /**
 59          * Externalizes this operation's name as a string.
 60          *
 61          * @implSpec this implementation returns the result of the expression {@code this.getClass().getName()}.
 62          *
 63          * @return the operation name
 64          */
 65         default String externalizeOpName() {
 66             return this.getClass().getName();
 67         }
 68 
 69         /**
 70          * Externalizes this operation's specific state as a map of attributes.
 71          *
 72          * <p>A null attribute value is represented by the constant
 73          * value {@link jdk.incubator.code.extern.ExternalizedOp#NULL_ATTRIBUTE_VALUE}.
 74          *
 75          * @implSpec this implementation returns an unmodifiable empty map.
 76          *
 77          * @return the operation's externalized state, as an unmodifiable map
 78          */
 79         default Map<String, Object> externalize() {
 80             return Map.of();
 81         }
 82     }
 83 
 84     /**
 85      * The attribute value that represents the external null value.
 86      */
 87     public static final Object NULL_ATTRIBUTE_VALUE = new Object();
 88 
 89     /**
 90      * Constructs a new externalized operation
 91      * @param name            the operation name
 92      * @param location        the source location associated with the operation, may be null
 93      * @param operands        the list of operands
 94      * @param successors      the list of successors
 95      * @param resultType      the operation result type
 96      * @param attributes      the operation's specific state as a map of attributes
 97      * @param bodyDefinitions the list of body builders for building the operation's bodies
 98      */
 99     public ExternalizedOp {
100         attributes = Map.copyOf(attributes);
101     }
102 
103     /**
104      * Externalizes an operation's content.
105      * <p>
106      * If the operation is an instanceof {@link Externalizable} then that instance is used to externalize the
107      * operation's name and the operation's specific state. Otherwise, the operation's name is externalized to the
108      * operation's class name and the operation's specific state is externalized as an empty unmodifiable map.
109      *
110      * @param cc the code context
111      * @param op the operation
112      * @return the operation's content.
113      */
114     public static ExternalizedOp externalizeOp(CodeContext cc, Op op) {
115         return new ExternalizedOp(
116                 (op instanceof ExternalizedOp.Externalizable eop)
117                         ? eop.externalizeOpName()
118                         : op.getClass().getName(),
119                 op.location(),
120                 cc.getValues(op.operands()),
121                 op.successors().stream().map(cc::getReferenceOrCreate).toList(),
122                 op.resultType(),
123                 (op instanceof ExternalizedOp.Externalizable eop)
124                         ? eop.externalize()
125                         : Map.of(),
126                 op.bodies().stream().map(b -> b.transform(cc, CodeTransformer.COPYING_TRANSFORMER)).toList()
127         );
128     }
129 }