1 /*
2 * Copyright 2014 - 2020 Rafael Winterhalter
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.bytebuddy.implementation.bytecode.constant;
17
18 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19 import net.bytebuddy.implementation.Implementation;
20 import net.bytebuddy.implementation.bytecode.StackManipulation;
21 import net.bytebuddy.implementation.bytecode.StackSize;
22 import net.bytebuddy.jar.asm.MethodVisitor;
23 import net.bytebuddy.jar.asm.Opcodes;
24
25
26 /**
27 * This class is responsible for loading any {@code int} constant onto the operand stack. Note that within the JVM,
28 * {@code boolean}, {@code byte}, {@code short} and {@code char} values are represented by integers and can therefore
29 * be loaded by using this class.
30 */
31 public enum IntegerConstant implements StackManipulation {
32
33 /**
34 * A JVM-type {@code int} constant of value {@code -1}.
35 */
36 MINUS_ONE(Opcodes.ICONST_M1),
37
38 /**
39 * A JVM-type {@code int} constant of value {@code 0}.
40 */
41 ZERO(Opcodes.ICONST_0),
42
43 /**
44 * A JVM-type {@code int} constant of value {@code 1}.
45 */
46 ONE(Opcodes.ICONST_1),
47
48 /**
49 * A JVM-type {@code int} constant of value {@code 2}.
50 */
51 TWO(Opcodes.ICONST_2),
52
53 /**
54 * A JVM-type {@code int} constant of value {@code 3}.
55 */
56 THREE(Opcodes.ICONST_3),
57
58 /**
59 * A JVM-type {@code int} constant of value {@code 4}.
60 */
61 FOUR(Opcodes.ICONST_4),
62
63 /**
64 * A JVM-type {@code int} constant of value {@code 5}.
65 */
66 FIVE(Opcodes.ICONST_5);
67
68 /**
69 * The size impact of loading an {@code int} value onto the operand stack.
70 */
71 private static final Size SIZE = StackSize.SINGLE.toIncreasingSize();
72
73 /**
74 * The shortcut opcode for loading a common {@code int}-compatible JVM value onto the operand stack.
75 */
76 private final int opcode;
77
78 /**
79 * Creates a new JVM-integer constant loading stack manipulation for a given shortcut opcode.
80 *
81 * @param opcode The shortcut opcode for loading a common {@code int}-compatible JVM value onto the operand stack.
82 */
83 IntegerConstant(int opcode) {
84 this.opcode = opcode;
85 }
86
87 /**
88 * Creates a stack manipulation for loading a boolean value onto the stack.
89 *
90 * @param value The {@code boolean} to load onto the stack.
91 * @return The stack manipulation for loading this {@code boolean}.
92 */
93 public static StackManipulation forValue(boolean value) {
94 return value ? ONE : ZERO;
95 }
96
97 /**
98 * Creates a stack manipulation for loading an {@code int} value onto the stack.
99 * <p> </p>
100 * This is achieved either by invoking a constant opcode, if any, or by creating a binary push operation.
101 *
102 * @param value The {@code int} (or {@code byte}, {@code short}, {@code char}) value to load onto the stack.
103 * @return A stack manipulation for loading the given value.
104 */
105 public static StackManipulation forValue(int value) {
106 switch (value) {
107 case -1:
108 return MINUS_ONE;
109 case 0:
110 return ZERO;
111 case 1:
112 return ONE;
113 case 2:
114 return TWO;
115 case 3:
116 return THREE;
117 case 4:
118 return FOUR;
119 case 5:
120 return FIVE;
121 default:
122 if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
123 return new SingleBytePush((byte) value);
124 } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
125 return new TwoBytePush((short) value);
126 } else {
127 return new ConstantPool(value);
128 }
129 }
130 }
131
132 /**
133 * {@inheritDoc}
134 */
135 public boolean isValid() {
136 return true;
137 }
138
139 /**
140 * {@inheritDoc}
141 */
142 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
143 methodVisitor.visitInsn(opcode);
144 return SIZE;
145 }
146
147 /**
148 * A stack manipulation that loads a JVM-integer value by a {@code BIPUSH} operation which is
149 * legal for single byte integer values.
150 */
151 @HashCodeAndEqualsPlugin.Enhance
152 protected static class SingleBytePush implements StackManipulation {
153
154 /**
155 * The single byte value to be loaded onto the operand stack.
156 */
157 private final byte value;
158
159 /**
160 * Creates a new {@code BIPUSH} stack manipulation for the given value.
161 *
162 * @param value The single byte value to be loaded onto the operand stack.
163 */
164 protected SingleBytePush(byte value) {
165 this.value = value;
166 }
167
168 /**
169 * {@inheritDoc}
170 */
171 public boolean isValid() {
172 return true;
173 }
174
175 /**
176 * {@inheritDoc}
177 */
178 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
179 methodVisitor.visitIntInsn(Opcodes.BIPUSH, value);
180 return SIZE;
181 }
182 }
183
184 /**
185 * A stack manipulation that loads a JVM-integer value by a {@code SIPUSH} operation which is
186 * legal for up to two byte integer values.
187 */
188 @HashCodeAndEqualsPlugin.Enhance
189 protected static class TwoBytePush implements StackManipulation {
190
191 /**
192 * The two byte value to be loaded onto the operand stack.
193 */
194 private final short value;
195
196 /**
197 * Creates a new {@code SIPUSH} stack manipulation for the given value.
198 *
199 * @param value The two byte value to be loaded onto the operand stack.
200 */
201 protected TwoBytePush(short value) {
202 this.value = value;
203 }
204
205 /**
206 * {@inheritDoc}
207 */
208 public boolean isValid() {
209 return true;
210 }
211
212 /**
213 * {@inheritDoc}
214 */
215 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
216 methodVisitor.visitIntInsn(Opcodes.SIPUSH, value);
217 return SIZE;
218 }
219 }
220
221 /**
222 * A stack manipulation that loads a JVM-integer value from a constant pool value onto the operand stack.
223 */
224 @HashCodeAndEqualsPlugin.Enhance
225 protected static class ConstantPool implements StackManipulation {
226
227 /**
228 * The JVM-integer value to load onto the operand stack.
229 */
230 private final int value;
231
232 /**
233 * Creates a new constant pool loading operation for a given JVM-integer.
234 *
235 * @param value The JVM-integer value to load onto the operand stack.
236 */
237 protected ConstantPool(int value) {
238 this.value = value;
239 }
240
241 /**
242 * {@inheritDoc}
243 */
244 public boolean isValid() {
245 return true;
246 }
247
248 /**
249 * {@inheritDoc}
250 */
251 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
252 methodVisitor.visitLdcInsn(value);
253 return SIZE;
254 }
255 }
256 }
257