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.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 import java.lang.classfile.TypeKind;
 25 
 26 import jdk.incubator.code.*;
 27 import jdk.incubator.code.extern.ExternalizedOp;
 28 import jdk.incubator.code.dialect.java.JavaType;
 29 import jdk.incubator.code.dialect.java.PrimitiveType;
 30 import jdk.incubator.code.internal.OpDeclaration;
 31 
 32 import java.util.List;
 33 import java.util.Map;
 34 
 35 sealed abstract class SlotOp extends Op {
 36     public static final String ATTRIBUTE_SLOT = "slot";
 37 
 38     public static SlotLoadOp load(int slot, TypeKind tk) {
 39         return new SlotLoadOp(slot, switch (tk) {
 40             case INT -> UnresolvedType.unresolvedInt();
 41             case REFERENCE -> UnresolvedType.unresolvedRef();
 42             case LONG -> JavaType.LONG;
 43             case DOUBLE -> JavaType.DOUBLE;
 44             case FLOAT -> JavaType.FLOAT;
 45             default -> throw new IllegalStateException("Unexpected load instruction type: " + tk);
 46         });
 47     }
 48 
 49     public static SlotStoreOp store(int slot, Value v) {
 50         return new SlotStoreOp(slot, v);
 51     }
 52 
 53     final int slot;
 54 
 55     protected SlotOp(SlotOp that, CodeContext cc) {
 56         super(that, cc);
 57         this.slot = that.slot;
 58     }
 59 
 60     protected SlotOp(List<? extends Value> operands, int slot) {
 61         super(operands);
 62         this.slot = slot;
 63     }
 64 
 65     public int slot() {
 66         return slot;
 67     }
 68 
 69     public abstract TypeKind typeKind();
 70 
 71     @Override
 72     public Map<String, Object> externalize() {
 73         return Map.of("", slot);
 74     }
 75 
 76     @OpDeclaration(SlotLoadOp.NAME)
 77     public static final class SlotLoadOp extends SlotOp {
 78         public static final String NAME = "slot.load";
 79 
 80         @Override
 81         public String externalizeOpName() {
 82             return NAME;
 83         }
 84 
 85         final CodeType resultType;
 86 
 87         public SlotLoadOp(ExternalizedOp def) {
 88             int slot = def.extractAttributeValue(ATTRIBUTE_SLOT, true,
 89                     v -> switch (v) {
 90                         case String s -> Integer.parseInt(s);
 91                         case Integer i -> i;
 92                         default -> throw new UnsupportedOperationException("Unsupported slot value:" + v);
 93                     });
 94             this(slot, def.resultType());
 95         }
 96 
 97         SlotLoadOp(SlotLoadOp that, CodeContext cc) {
 98             super(that, cc);
 99             this.resultType = that.resultType;
100         }
101 
102         @Override
103         public SlotLoadOp transform(CodeContext cc, CodeTransformer ct) {
104             return new SlotLoadOp(this, cc);
105         }
106 
107         SlotLoadOp(int slot, CodeType resultType) {
108             super(List.of(), slot);
109             this.resultType = resultType;
110         }
111 
112         @Override
113         public CodeType resultType() {
114             return resultType;
115         }
116 
117         @Override
118         public TypeKind typeKind() {
119             return toTypeKind(resultType);
120         }
121 
122         @Override
123         public String toString() {
124             return "block_" + ancestorBlock().index() + " " + ancestorBlock().ops().indexOf(this) + ": #" + slot + " LOAD " + typeKind();
125         }
126     }
127 
128     @OpDeclaration(SlotStoreOp.NAME)
129     public static final class SlotStoreOp extends SlotOp {
130         public static final String NAME = "slot.store";
131 
132         @Override
133         public String externalizeOpName() {
134             return NAME;
135         }
136 
137         public SlotStoreOp(ExternalizedOp def) {
138             int slot = def.extractAttributeValue(ATTRIBUTE_SLOT, true,
139                     v -> switch (v) {
140                         case String s -> Integer.parseInt(s);
141                         case Integer i -> i;
142                         default -> throw new UnsupportedOperationException("Unsupported slot value:" + v);
143                     });
144             this(slot, def.operands().getFirst());
145         }
146 
147         SlotStoreOp(SlotStoreOp that, CodeContext cc) {
148             super(that, cc);
149         }
150 
151         @Override
152         public SlotStoreOp transform(CodeContext cc, CodeTransformer ct) {
153             return new SlotStoreOp(this, cc);
154         }
155 
156         SlotStoreOp(int slot, Value v) {
157             super(List.of(v), slot);
158         }
159 
160         @Override
161         public CodeType resultType() {
162             return JavaType.VOID;
163         }
164 
165         @Override
166         public TypeKind typeKind() {
167             return toTypeKind(operands().getFirst().type());
168         }
169 
170         @Override
171         public String toString() {
172             return "block_" + ancestorBlock().index() + " " + ancestorBlock().ops().indexOf(this) + ": #" + slot + " STORE " + typeKind();
173         }
174     }
175 
176     private static TypeKind toTypeKind(CodeType type) {
177         return switch (type) {
178             case UnresolvedType.Int _ ->
179                 TypeKind.INT;
180             case PrimitiveType pt ->
181                 TypeKind.from(pt.toNominalDescriptor()).asLoadable();
182             default ->
183                 TypeKind.REFERENCE;
184         };
185     }
186 }