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