1 /*
  2  * Copyright (c) 2024, 2025, 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 import java.lang.classfile.TypeKind;
 27 
 28 import jdk.incubator.code.*;
 29 import jdk.incubator.code.extern.ExternalizedOp;
 30 import jdk.incubator.code.dialect.java.JavaType;
 31 import jdk.incubator.code.dialect.java.PrimitiveType;
 32 import jdk.incubator.code.internal.OpDeclaration;
 33 
 34 import java.util.List;
 35 import java.util.Map;
 36 
 37 sealed abstract class SlotOp extends Op {
 38     public static final String ATTRIBUTE_SLOT = "slot";
 39 
 40     public static SlotLoadOp load(int slot, TypeKind tk) {
 41         return new SlotLoadOp(slot, switch (tk) {
 42             case INT -> UnresolvedType.unresolvedInt();
 43             case REFERENCE -> UnresolvedType.unresolvedRef();
 44             case LONG -> JavaType.LONG;
 45             case DOUBLE -> JavaType.DOUBLE;
 46             case FLOAT -> JavaType.FLOAT;
 47             default -> throw new IllegalStateException("Unexpected load instruction type: " + tk);
 48         });
 49     }
 50 
 51     public static SlotStoreOp store(int slot, Value v) {
 52         return new SlotStoreOp(slot, v);
 53     }
 54 
 55     final int slot;
 56 
 57     protected SlotOp(SlotOp that, CopyContext cc) {
 58         super(that, cc);
 59         this.slot = that.slot;
 60     }
 61 
 62     protected SlotOp(List<? extends Value> operands, int slot) {
 63         super(operands);
 64         this.slot = slot;
 65     }
 66 
 67     public int slot() {
 68         return slot;
 69     }
 70 
 71     public abstract TypeKind typeKind();
 72 
 73     @Override
 74     public Map<String, Object> externalize() {
 75         return Map.of("", slot);
 76     }
 77 
 78     @OpDeclaration(SlotLoadOp.NAME)
 79     public static final class SlotLoadOp extends SlotOp {
 80         public static final String NAME = "slot.load";
 81 
 82         @Override
 83         public String externalizeOpName() {
 84             return NAME;
 85         }
 86 
 87         final TypeElement resultType;
 88 
 89         public SlotLoadOp(ExternalizedOp def) {
 90             int slot = def.extractAttributeValue(ATTRIBUTE_SLOT, true,
 91                     v -> switch (v) {
 92                         case String s -> Integer.parseInt(s);
 93                         case Integer i -> i;
 94                         default -> throw new UnsupportedOperationException("Unsupported slot value:" + v);
 95                     });
 96             this(slot, def.resultType());
 97         }
 98 
 99         SlotLoadOp(SlotLoadOp that, CopyContext cc) {
100             super(that, cc);
101             this.resultType = that.resultType;
102         }
103 
104         @Override
105         public SlotLoadOp transform(CopyContext cc, OpTransformer ot) {
106             return new SlotLoadOp(this, cc);
107         }
108 
109         SlotLoadOp(int slot, TypeElement resultType) {
110             super(List.of(), slot);
111             this.resultType = resultType;
112         }
113 
114         @Override
115         public TypeElement resultType() {
116             return resultType;
117         }
118 
119         @Override
120         public TypeKind typeKind() {
121             return toTypeKind(resultType);
122         }
123 
124         @Override
125         public String toString() {
126             return "block_" + ancestorBlock().index() + " " + ancestorBlock().ops().indexOf(this) + ": #" + slot + " LOAD " + typeKind();
127         }
128     }
129 
130     @OpDeclaration(SlotStoreOp.NAME)
131     public static final class SlotStoreOp extends SlotOp {
132         public static final String NAME = "slot.store";
133 
134         @Override
135         public String externalizeOpName() {
136             return NAME;
137         }
138 
139         public SlotStoreOp(ExternalizedOp def) {
140             int slot = def.extractAttributeValue(ATTRIBUTE_SLOT, true,
141                     v -> switch (v) {
142                         case String s -> Integer.parseInt(s);
143                         case Integer i -> i;
144                         default -> throw new UnsupportedOperationException("Unsupported slot value:" + v);
145                     });
146             this(slot, def.operands().getFirst());
147         }
148 
149         SlotStoreOp(SlotStoreOp that, CopyContext cc) {
150             super(that, cc);
151         }
152 
153         @Override
154         public SlotStoreOp transform(CopyContext cc, OpTransformer ot) {
155             return new SlotStoreOp(this, cc);
156         }
157 
158         SlotStoreOp(int slot, Value v) {
159             super(List.of(v), slot);
160         }
161 
162         @Override
163         public TypeElement resultType() {
164             return JavaType.VOID;
165         }
166 
167         @Override
168         public TypeKind typeKind() {
169             return toTypeKind(operands().getFirst().type());
170         }
171 
172         @Override
173         public String toString() {
174             return "block_" + ancestorBlock().index() + " " + ancestorBlock().ops().indexOf(this) + ": #" + slot + " STORE " + typeKind();
175         }
176     }
177 
178     private static TypeKind toTypeKind(TypeElement type) {
179         return switch (type) {
180             case UnresolvedType.Int _ ->
181                 TypeKind.INT;
182             case PrimitiveType pt ->
183                 TypeKind.from(pt.toNominalDescriptor()).asLoadable();
184             default ->
185                 TypeKind.REFERENCE;
186         };
187     }
188 }