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