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 import java.util.function.Function;
 32 
 33 /**
 34  * An operation's externalized state (a record) that can be utilized to construct an instance
 35  * of an {@link Op} associated with that state, such as the operation's name.
 36  *
 37  * @param name            the operation name
 38  * @param location        the source location associated with the operation, may be null
 39  * @param operands        the list of operands
 40  * @param successors      the list of successors
 41  * @param resultType      the operation result type
 42  * @param attributes      the operation's specific state as a map of attributes
 43  * @param bodyDefinitions the list of body builders for building the operation's bodies
 44  * @apiNote Deserializers of operations may utilize this record to construct operations,
 45  * thereby separating the specifics of deserializing from construction.
 46  */
 47 public record ExternalizedOp(String name,
 48                              Op.Location location,
 49                              List<Value> operands,
 50                              List<Block.Reference> successors,
 51                              CodeType resultType,
 52                              Map<String, Object> attributes,
 53                              List<Body.Builder> bodyDefinitions) {
 54 
 55     /**
 56      * The attribute value that represents the external null value.
 57      */
 58     public static final Object NULL_ATTRIBUTE_VALUE = new Object();
 59 
 60     /**
 61      * Constructs a new externalized operation
 62      * @param name            the operation name
 63      * @param location        the source location associated with the operation, may be null
 64      * @param operands        the list of operands
 65      * @param successors      the list of successors
 66      * @param resultType      the operation result type
 67      * @param attributes      the operation's specific state as a map of attributes
 68      * @param bodyDefinitions the list of body builders for building the operation's bodies
 69      */
 70     public ExternalizedOp {
 71         attributes = Map.copyOf(attributes);
 72     }
 73 
 74     /**
 75      * Gets an attribute value from the attributes map, converts the value by applying it
 76      * to mapping function, and returns the result.
 77      *
 78      * <p>If the attribute is a default attribute then this method first attempts to
 79      * get the attribute whose name is the empty string, otherwise if there is no such
 80      * attribute present or the attribute is not a default attribute then this method
 81      * attempts to get the attribute with the given name.
 82      *
 83      * <p>On successfully obtaining the attribute its value is converted by applying the value
 84      * to the mapping function. A {@code null} value is represented by the value
 85      * {@link ExternalizedOp#NULL_ATTRIBUTE_VALUE}.
 86      *
 87      * <p>If no attribute is present the {@code null} value is applied to the mapping function.
 88      *
 89      * @param name      the attribute name.
 90      * @param isDefault true if the attribute is a default attribute
 91      * @param mapper    the function used to convert the attribute value
 92      * @param <T>       the converted attribute value type
 93      * @return the converted attribute value
 94      */
 95     public <T> T extractAttributeValue(String name, boolean isDefault, Function<Object, T> mapper) {
 96         Object value = null;
 97         if (isDefault && attributes.containsKey("")) {
 98             value = attributes.get("");
 99             assert value != null;
100         }
101 
102         if (value == null && attributes.containsKey(name)) {
103             value = attributes.get(name);
104             assert value != null;
105         }
106 
107         return mapper.apply(value);
108     }
109 
110     /**
111      * Externalizes an operation's content.
112      * <p>
113      * If the operation is an instanceof {@code ExternalizableOp} then the operation's
114      * specific content is externalized to an attribute map, otherwise the attribute map
115      * is empty.
116      *
117      * @param cc the code context
118      * @param op the operation
119      * @return the operation's content.
120      */
121     public static ExternalizedOp externalizeOp(CodeContext cc, Op op) {
122         return new ExternalizedOp(
123                 op.externalizeOpName(),
124                 op.location(),
125                 cc.getValues(op.operands()),
126                 op.successors().stream().map(cc::getReferenceOrCreate).toList(),
127                 op.resultType(),
128                 op.externalize(),
129                 op.bodies().stream().map(b -> b.transform(cc, CodeTransformer.COPYING_TRANSFORMER)).toList()
130         );
131     }
132 }