Skip to content

Commit a3140ce

Browse files
authored
Add PrimitiveNarrowingDelegate (#1805)
1 parent 0c4f598 commit a3140ce

File tree

5 files changed

+633
-0
lines changed

5 files changed

+633
-0
lines changed
Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
/*
2+
* Copyright 2014 - Present 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.assign.primitive;
17+
18+
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19+
import net.bytebuddy.description.type.TypeDefinition;
20+
import net.bytebuddy.implementation.Implementation;
21+
import net.bytebuddy.implementation.bytecode.StackManipulation;
22+
import net.bytebuddy.implementation.bytecode.StackSize;
23+
import org.objectweb.asm.MethodVisitor;
24+
import org.objectweb.asm.Opcodes;
25+
26+
/**
27+
* This delegate is responsible for narrowing a primitive type to represent a <i>smaller</i> primitive type. The
28+
* rules for this narrowing are equivalent to those in the <a href="http://docs.oracle.com/javase/specs/">JLS</a>.
29+
* This class also includes the byte-to-char conversion in widening and narrowing primitive conversions.
30+
*/
31+
public enum PrimitiveNarrowingDelegate {
32+
33+
/**
34+
* The narrowing delegate for {@code boolean} values.
35+
*/
36+
BOOLEAN(StackManipulation.Trivial.INSTANCE, // to boolean
37+
StackManipulation.Illegal.INSTANCE, // to byte
38+
StackManipulation.Illegal.INSTANCE, // to short
39+
StackManipulation.Illegal.INSTANCE, // to character
40+
StackManipulation.Illegal.INSTANCE, // to integer
41+
StackManipulation.Illegal.INSTANCE, // to long
42+
StackManipulation.Illegal.INSTANCE, // to float
43+
StackManipulation.Illegal.INSTANCE), // to double
44+
45+
/**
46+
* The narrowing delegate for {@code byte} values.
47+
*/
48+
BYTE(StackManipulation.Illegal.INSTANCE, // to boolean
49+
StackManipulation.Trivial.INSTANCE, // to byte
50+
StackManipulation.Illegal.INSTANCE, // to short
51+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
52+
new int[]{Opcodes.I2C}, StackSize.ZERO.toDecreasingSize()), // to character
53+
StackManipulation.Illegal.INSTANCE, // to integer
54+
StackManipulation.Illegal.INSTANCE, // to long
55+
StackManipulation.Illegal.INSTANCE, // to float
56+
StackManipulation.Illegal.INSTANCE), // to double
57+
58+
/**
59+
* The narrowing delegate for {@code short} values.
60+
*/
61+
SHORT(StackManipulation.Illegal.INSTANCE, // to boolean
62+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
63+
new int[]{Opcodes.I2B}, StackSize.ZERO.toDecreasingSize()), // to byte
64+
StackManipulation.Trivial.INSTANCE, // to short
65+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
66+
new int[]{Opcodes.I2C}, StackSize.ZERO.toDecreasingSize()), // to character
67+
StackManipulation.Illegal.INSTANCE, // to integer
68+
StackManipulation.Illegal.INSTANCE, // to long
69+
StackManipulation.Illegal.INSTANCE, // to float
70+
StackManipulation.Illegal.INSTANCE), // to double
71+
72+
/**
73+
* The narrowing delegate for {@code char} values.
74+
*/
75+
CHARACTER(StackManipulation.Illegal.INSTANCE, // to boolean
76+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
77+
new int[]{Opcodes.I2B}, StackSize.ZERO.toDecreasingSize()), // to byte
78+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
79+
new int[]{Opcodes.I2S}, StackSize.ZERO.toDecreasingSize()), // to short
80+
StackManipulation.Trivial.INSTANCE, // to character
81+
StackManipulation.Illegal.INSTANCE, // to integer
82+
StackManipulation.Illegal.INSTANCE, // to long
83+
StackManipulation.Illegal.INSTANCE, // to float
84+
StackManipulation.Illegal.INSTANCE), // to double
85+
86+
/**
87+
* The narrowing delegate for {@code int} values.
88+
*/
89+
INTEGER(StackManipulation.Illegal.INSTANCE, // to boolean
90+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
91+
new int[]{Opcodes.I2B}, StackSize.ZERO.toDecreasingSize()), // to byte
92+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
93+
new int[]{Opcodes.I2S}, StackSize.ZERO.toDecreasingSize()), // to short
94+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
95+
new int[]{Opcodes.I2C}, StackSize.ZERO.toDecreasingSize()), // to character
96+
StackManipulation.Trivial.INSTANCE, // to integer
97+
StackManipulation.Illegal.INSTANCE, // to long
98+
StackManipulation.Illegal.INSTANCE, // to float
99+
StackManipulation.Illegal.INSTANCE), // to double
100+
101+
/**
102+
* The narrowing delegate for {@code long} values.
103+
*/
104+
LONG(StackManipulation.Illegal.INSTANCE, // to boolean
105+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
106+
new int[]{Opcodes.L2I, Opcodes.I2B}, StackSize.SINGLE.toDecreasingSize()), // to byte
107+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
108+
new int[]{Opcodes.L2I, Opcodes.I2S}, StackSize.SINGLE.toDecreasingSize()), // to short
109+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
110+
new int[]{Opcodes.L2I, Opcodes.I2C}, StackSize.SINGLE.toDecreasingSize()), // to character
111+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
112+
new int[]{Opcodes.L2I}, StackSize.SINGLE.toDecreasingSize()), // to integer
113+
StackManipulation.Trivial.INSTANCE, // to long
114+
StackManipulation.Illegal.INSTANCE, // to float
115+
StackManipulation.Illegal.INSTANCE), // to double
116+
117+
/**
118+
* The narrowing delegate for {@code float} values.
119+
*/
120+
FLOAT(StackManipulation.Illegal.INSTANCE, // to boolean
121+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
122+
new int[]{Opcodes.F2I, Opcodes.I2B}, StackSize.ZERO.toDecreasingSize()), // to byte
123+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
124+
new int[]{Opcodes.F2I, Opcodes.I2S}, StackSize.ZERO.toDecreasingSize()), // to short
125+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
126+
new int[]{Opcodes.F2I, Opcodes.I2C}, StackSize.ZERO.toDecreasingSize()), // to character
127+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
128+
new int[]{Opcodes.F2I}, StackSize.ZERO.toDecreasingSize()), // to integer
129+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
130+
new int[]{Opcodes.F2L}, StackSize.SINGLE.toIncreasingSize()), // to long
131+
StackManipulation.Trivial.INSTANCE, // to float
132+
StackManipulation.Illegal.INSTANCE), // to double
133+
134+
/**
135+
* The narrowing delegate for {@code double} values.
136+
*/
137+
DOUBLE(StackManipulation.Illegal.INSTANCE, // to boolean
138+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
139+
new int[]{Opcodes.D2I, Opcodes.I2B}, StackSize.SINGLE.toDecreasingSize()), // to byte
140+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
141+
new int[]{Opcodes.D2I, Opcodes.I2S}, StackSize.SINGLE.toDecreasingSize()), // to short
142+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
143+
new int[]{Opcodes.D2I, Opcodes.I2C}, StackSize.SINGLE.toDecreasingSize()), // to character
144+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
145+
new int[]{Opcodes.D2I}, StackSize.SINGLE.toDecreasingSize()), // to integer
146+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
147+
new int[]{Opcodes.D2L}, StackSize.ZERO.toDecreasingSize()), // to long
148+
new PrimitiveNarrowingDelegate.NarrowingStackManipulation(
149+
new int[]{Opcodes.D2F}, StackSize.SINGLE.toDecreasingSize()), // to float
150+
StackManipulation.Trivial.INSTANCE); // to double
151+
152+
/**
153+
* A stack manipulation that narrows the type that is represented by this instance to a {@code boolean}.
154+
*/
155+
private final StackManipulation toBooleanStackManipulation;
156+
157+
/**
158+
* A stack manipulation that narrows the type that is represented by this instance to a {@code byte}.
159+
*/
160+
private final StackManipulation toByteStackManipulation;
161+
162+
/**
163+
* A stack manipulation that narrows the type that is represented by this instance to a {@code short}.
164+
*/
165+
private final StackManipulation toShortStackManipulation;
166+
167+
/**
168+
* A stack manipulation that narrows the type that is represented by this instance to a {@code char}.
169+
*/
170+
private final StackManipulation toCharacterStackManipulation;
171+
172+
/**
173+
* A stack manipulation that narrows the type that is represented by this instance to a {@code int}.
174+
*/
175+
private final StackManipulation toIntegerStackManipulation;
176+
177+
/**
178+
* A stack manipulation that narrows the type that is represented by this instance to a {@code long}.
179+
*/
180+
private final StackManipulation toLongStackManipulation;
181+
182+
/**
183+
* A stack manipulation that narrows the type that is represented by this instance to a {@code float}.
184+
*/
185+
private final StackManipulation toFloatStackManipulation;
186+
187+
/**
188+
* A stack manipulation that narrows the type that is represented by this instance to a {@code double}.
189+
*/
190+
private final StackManipulation toDoubleStackManipulation;
191+
192+
/**
193+
* Creates a new primitive narrowing delegate.
194+
*
195+
* @param toBooleanStackManipulation A stack manipulation that narrows the type that is represented by this
196+
* instance to a {@code boolean}.
197+
* @param toByteStackManipulation A stack manipulation that narrows the type that is represented by this
198+
* instance to a {@code byte}.
199+
* @param toShortStackManipulation A stack manipulation that narrows the type that is represented by this
200+
* instance to a {@code short}.
201+
* @param toCharacterStackManipulation A stack manipulation that narrows the type that is represented by this
202+
* instance to a {@code char}.
203+
* @param toIntegerStackManipulation A stack manipulation that narrows the type that is represented by this
204+
* instance to a {@code int}.
205+
* @param toLongStackManipulation A stack manipulation that narrows the type that is represented by this
206+
* instance to a {@code long}.
207+
* @param toFloatStackManipulation A stack manipulation that narrows the type that is represented by this
208+
* instance to a {@code float}.
209+
* @param toDoubleStackManipulation A stack manipulation that narrows the type that is represented by this
210+
* instance to a {@code double}.
211+
*/
212+
PrimitiveNarrowingDelegate(StackManipulation toBooleanStackManipulation,
213+
StackManipulation toByteStackManipulation,
214+
StackManipulation toShortStackManipulation,
215+
StackManipulation toCharacterStackManipulation,
216+
StackManipulation toIntegerStackManipulation,
217+
StackManipulation toLongStackManipulation,
218+
StackManipulation toFloatStackManipulation,
219+
StackManipulation toDoubleStackManipulation) {
220+
this.toBooleanStackManipulation = toBooleanStackManipulation;
221+
this.toByteStackManipulation = toByteStackManipulation;
222+
this.toShortStackManipulation = toShortStackManipulation;
223+
this.toCharacterStackManipulation = toCharacterStackManipulation;
224+
this.toIntegerStackManipulation = toIntegerStackManipulation;
225+
this.toLongStackManipulation = toLongStackManipulation;
226+
this.toFloatStackManipulation = toFloatStackManipulation;
227+
this.toDoubleStackManipulation = toDoubleStackManipulation;
228+
}
229+
230+
/**
231+
* Locates the delegate that is capable of narrowing the given type into another type.
232+
*
233+
* @param typeDefinition A non-void primitive type that is to be narrowed into another type.
234+
* @return A delegate for the given type.
235+
*/
236+
public static PrimitiveNarrowingDelegate forPrimitive(TypeDefinition typeDefinition) {
237+
if (typeDefinition.represents(boolean.class)) {
238+
return BOOLEAN;
239+
} else if (typeDefinition.represents(byte.class)) {
240+
return BYTE;
241+
} else if (typeDefinition.represents(short.class)) {
242+
return SHORT;
243+
} else if (typeDefinition.represents(char.class)) {
244+
return CHARACTER;
245+
} else if (typeDefinition.represents(int.class)) {
246+
return INTEGER;
247+
} else if (typeDefinition.represents(long.class)) {
248+
return LONG;
249+
} else if (typeDefinition.represents(float.class)) {
250+
return FLOAT;
251+
} else if (typeDefinition.represents(double.class)) {
252+
return DOUBLE;
253+
} else {
254+
throw new IllegalArgumentException("Not a primitive, non-void type: " + typeDefinition);
255+
}
256+
}
257+
258+
/**
259+
* Attempts to narrow the represented type into another type.
260+
*
261+
* @param typeDefinition A non-void primitive type that is the expected result of the narrowing operation.
262+
* @return A narrowing instruction or an illegal stack manipulation if such narrowing is not legitimate.
263+
*/
264+
public StackManipulation narrowTo(TypeDefinition typeDefinition) {
265+
if (typeDefinition.represents(boolean.class)) {
266+
return toBooleanStackManipulation;
267+
} else if (typeDefinition.represents(byte.class)) {
268+
return toByteStackManipulation;
269+
} else if (typeDefinition.represents(short.class)) {
270+
return toShortStackManipulation;
271+
} else if (typeDefinition.represents(char.class)) {
272+
return toCharacterStackManipulation;
273+
} else if (typeDefinition.represents(int.class)) {
274+
return toIntegerStackManipulation;
275+
} else if (typeDefinition.represents(long.class)) {
276+
return toLongStackManipulation;
277+
} else if (typeDefinition.represents(float.class)) {
278+
return toFloatStackManipulation;
279+
} else if (typeDefinition.represents(double.class)) {
280+
return toDoubleStackManipulation;
281+
} else {
282+
throw new IllegalArgumentException("Not a primitive non-void type: " + typeDefinition);
283+
}
284+
}
285+
286+
/**
287+
* A stack manipulation that narrows a primitive type into a smaller primitive type.
288+
*/
289+
@HashCodeAndEqualsPlugin.Enhance
290+
protected static class NarrowingStackManipulation extends StackManipulation.AbstractBase {
291+
292+
/**
293+
* The opcode for executing the conversion.
294+
*/
295+
private final int[] conversionOpcodes;
296+
297+
/**
298+
* The size change of applying the conversion.
299+
*/
300+
private final Size size;
301+
302+
/**
303+
* Creates a new narrowing stack manipulation.
304+
*
305+
* @param conversionOpcodes The opcodes for executing the conversion.
306+
* @param size The size change of applying the conversion.
307+
*/
308+
protected NarrowingStackManipulation(int[] conversionOpcodes, Size size) {
309+
this.conversionOpcodes = conversionOpcodes;
310+
this.size = size;
311+
}
312+
313+
/**
314+
* {@inheritDoc}
315+
*/
316+
public Size apply(MethodVisitor methodVisitor, Implementation.Context context) {
317+
for (int conversionOpcode : conversionOpcodes) {
318+
methodVisitor.visitInsn(conversionOpcode);
319+
}
320+
return size;
321+
}
322+
}
323+
}

0 commit comments

Comments
 (0)