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