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>&nbsp;</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