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 }