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(String name, List<? extends Value> operands, int slot) {
 64         super(name, 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         final TypeElement resultType;
 84 
 85         public SlotLoadOp(ExternalizedOp def) {
 86             int slot = def.extractAttributeValue(ATTRIBUTE_SLOT, true,
 87                     v -> switch (v) {
 88                         case String s -> Integer.parseInt(s);
 89                         case Integer i -> i;
 90                         default -> throw new UnsupportedOperationException("Unsupported slot value:" + v);
 91                     });
 92             this(slot, def.resultType());
 93         }
 94 
 95         SlotLoadOp(SlotLoadOp that, CopyContext cc) {
 96             super(that, cc);
 97             this.resultType = that.resultType;
 98         }
 99 
100         @Override
101         public SlotLoadOp transform(CopyContext cc, OpTransformer ot) {
102             return new SlotLoadOp(this, cc);
103         }
104 
105         SlotLoadOp(int slot, TypeElement resultType) {
106             super(NAME, List.of(), slot);
107             this.resultType = resultType;
108         }
109 
110         @Override
111         public TypeElement resultType() {
112             return resultType;
113         }
114 
115         @Override
116         public TypeKind typeKind() {
117             return toTypeKind(resultType);
118         }
119 
120         @Override
121         public String toString() {
122             return "block_" + parentBlock().index() + " " + parentBlock().ops().indexOf(this) + ": #" + slot + " LOAD " + typeKind();
123         }
124     }
125 
126     @OpDeclaration(SlotStoreOp.NAME)
127     public static final class SlotStoreOp extends SlotOp {
128         public static final String NAME = "slot.store";
129 
130         public SlotStoreOp(ExternalizedOp def) {
131             int slot = def.extractAttributeValue(ATTRIBUTE_SLOT, true,
132                     v -> switch (v) {
133                         case String s -> Integer.parseInt(s);
134                         case Integer i -> i;
135                         default -> throw new UnsupportedOperationException("Unsupported slot value:" + v);
136                     });
137             this(slot, def.operands().getFirst());
138         }
139 
140         SlotStoreOp(SlotStoreOp that, CopyContext cc) {
141             super(that, cc);
142         }
143 
144         @Override
145         public SlotStoreOp transform(CopyContext cc, OpTransformer ot) {
146             return new SlotStoreOp(this, cc);
147         }
148 
149         SlotStoreOp(int slot, Value v) {
150             super(NAME, List.of(v), slot);
151         }
152 
153         @Override
154         public TypeElement resultType() {
155             return JavaType.VOID;
156         }
157 
158         @Override
159         public TypeKind typeKind() {
160             return toTypeKind(operands().getFirst().type());
161         }
162 
163         @Override
164         public String toString() {
165             return "block_" + parentBlock().index() + " " + parentBlock().ops().indexOf(this) + ": #" + slot + " STORE " + typeKind();
166         }
167     }
168 
169     private static TypeKind toTypeKind(TypeElement type) {
170         return switch (type) {
171             case UnresolvedType.Int _ ->
172                 TypeKind.INT;
173             case PrimitiveType pt ->
174                 TypeKind.from(pt.toNominalDescriptor()).asLoadable();
175             default ->
176                 TypeKind.REFERENCE;
177         };
178     }
179 }