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.ClassFileVersion;
19 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20 import net.bytebuddy.description.type.TypeDescription;
21 import net.bytebuddy.implementation.Implementation;
22 import net.bytebuddy.implementation.bytecode.StackManipulation;
23 import net.bytebuddy.implementation.bytecode.StackSize;
24 import net.bytebuddy.jar.asm.MethodVisitor;
25 import net.bytebuddy.jar.asm.Opcodes;
26 import net.bytebuddy.jar.asm.Type;
27
28 /**
29 * Represents a constant representing any loaded Java {@link java.lang.Class}.
30 */
31 public enum ClassConstant implements StackManipulation {
32
33 /**
34 * The {@code void} type.
35 */
36 VOID(Void.class),
37
38 /**
39 * The {@code boolean} type.
40 */
41 BOOLEAN(Boolean.class),
42
43 /**
44 * The {@code byte} type.
45 */
46 BYTE(Byte.class),
47
48 /**
49 * The {@code short} type.
50 */
51 SHORT(Short.class),
52
53 /**
54 * The {@code char} type.
55 */
56 CHARACTER(Character.class),
57
58 /**
59 * The {@code int} type.
60 */
61 INTEGER(Integer.class),
62
63 /**
64 * The {@code long} type.
65 */
66 LONG(Long.class),
67
68 /**
69 * The {@code float} type.
70 */
71 FLOAT(Float.class),
72
73 /**
74 * The {@code double} type.
75 */
76 DOUBLE(Double.class);
77
78 /**
79 * The size of a {@link java.lang.Class} on the operand stack.
80 */
81 private static final Size SIZE = StackSize.SINGLE.toIncreasingSize();
82
83 /**
84 * The field name that stores a reference to the primitive type representation.
85 */
86 private static final String PRIMITIVE_TYPE_FIELD = "TYPE";
87
88 /**
89 * The descriptor of the {@link java.lang.Class} type.
90 */
91 private static final String CLASS_TYPE_INTERNAL_NAME = "Ljava/lang/Class;";
92
93 /**
94 * The internal name of the type owning the field.
95 */
96 private final String fieldOwnerInternalName;
97
98 /**
99 * Creates a new class constant for a primitive type.
100 *
101 * @param type The primitive type to represent.
102 */
103 ClassConstant(Class<?> type) {
104 fieldOwnerInternalName = Type.getInternalName(type);
105 }
106
107 /**
108 * Returns a stack manipulation that loads a {@link java.lang.Class} type onto the operand stack which
109 * represents the given type.
110 *
111 * @param typeDescription The type to load onto the operand stack.
112 * @return The corresponding stack manipulation.
113 */
114 public static StackManipulation of(TypeDescription typeDescription) {
115 if (!typeDescription.isPrimitive()) {
116 return new ForReferenceType(typeDescription);
117 } else if (typeDescription.represents(boolean.class)) {
118 return BOOLEAN;
119 } else if (typeDescription.represents(byte.class)) {
120 return BYTE;
121 } else if (typeDescription.represents(short.class)) {
122 return SHORT;
123 } else if (typeDescription.represents(char.class)) {
124 return CHARACTER;
125 } else if (typeDescription.represents(int.class)) {
126 return INTEGER;
127 } else if (typeDescription.represents(long.class)) {
128 return LONG;
129 } else if (typeDescription.represents(float.class)) {
130 return FLOAT;
131 } else if (typeDescription.represents(double.class)) {
132 return DOUBLE;
133 } else {
134 return VOID;
135 }
136 }
137
138 /**
139 * {@inheritDoc}
140 */
141 public boolean isValid() {
142 return true;
143 }
144
145 /**
146 * {@inheritDoc}
147 */
148 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
149 methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, fieldOwnerInternalName, PRIMITIVE_TYPE_FIELD, CLASS_TYPE_INTERNAL_NAME);
150 return SIZE;
151 }
152
153 /**
154 * A class constant for a non-primitive {@link java.lang.Class}.
155 */
156 @HashCodeAndEqualsPlugin.Enhance
157 protected static class ForReferenceType implements StackManipulation {
158
159 /**
160 * The type which should be loaded onto the operand stack as a class value.
161 */
162 private final TypeDescription typeDescription;
163
164 /**
165 * Creates a stack manipulation that represents loading a class constant onto the stack.
166 *
167 * @param typeDescription A description of the class to load onto the stack.
168 */
169 protected ForReferenceType(TypeDescription typeDescription) {
170 this.typeDescription = typeDescription;
171 }
172
173 /**
174 * {@inheritDoc}
175 */
176 public boolean isValid() {
177 return true;
178 }
179
180 /**
181 * {@inheritDoc}
182 */
183 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
184 if (implementationContext.getClassFileVersion().isAtLeast(ClassFileVersion.JAVA_V5) && typeDescription.isVisibleTo(implementationContext.getInstrumentedType())) {
185 methodVisitor.visitLdcInsn(Type.getType(typeDescription.getDescriptor()));
186 } else {
187 methodVisitor.visitLdcInsn(typeDescription.getName());
188 methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
189 }
190 return SIZE;
191 }
192 }
193 }
194