28
28
import org .springframework .util .Assert ;
29
29
30
30
/**
31
- * Manages the class being generated by the compilation process. It records
32
- * intermediate compilation state as the bytecode is generated. It also includes
33
- * various bytecode generation helper functions.
31
+ * Manages the class being generated by the compilation process.
32
+ *
33
+ * <p>Records intermediate compilation state as the bytecode is generated.
34
+ * Also includes various bytecode generation helper functions.
34
35
*
35
36
* @author Andy Clement
37
+ * @author Juergen Hoeller
36
38
* @since 4.1
37
39
*/
38
40
public class CodeFlow implements Opcodes {
39
41
42
+ /**
43
+ * Name of the class being generated. Typically used when generating code
44
+ * that accesses freshly generated fields on the generated type.
45
+ */
46
+ private final String className ;
47
+
48
+ /**
49
+ * The current class being generated.
50
+ */
51
+ private final ClassWriter classWriter ;
52
+
40
53
/**
41
54
* Record the type of what is on top of the bytecode stack (i.e. the type of the
42
55
* output from the previous expression component). New scopes are used to evaluate
@@ -45,31 +58,20 @@ public class CodeFlow implements Opcodes {
45
58
*/
46
59
private final Stack <ArrayList <String >> compilationScopes ;
47
60
48
- /**
49
- * The current class being generated
50
- */
51
- private ClassWriter cw ;
52
-
53
61
/**
54
62
* As SpEL ast nodes are called to generate code for the main evaluation method
55
63
* they can register to add a field to this class. Any registered FieldAdders
56
64
* will be called after the main evaluation function has finished being generated.
57
65
*/
58
- private List <FieldAdder > fieldAdders = null ;
66
+ private List <FieldAdder > fieldAdders ;
59
67
60
68
/**
61
69
* As SpEL ast nodes are called to generate code for the main evaluation method
62
70
* they can register to add code to a static initializer in the class. Any
63
71
* registered ClinitAdders will be called after the main evaluation function
64
72
* has finished being generated.
65
73
*/
66
- private List <ClinitAdder > clinitAdders = null ;
67
-
68
- /**
69
- * Name of the class being generated. Typically used when generating code
70
- * that accesses freshly generated fields on the generated type.
71
- */
72
- private String clazzName ;
74
+ private List <ClinitAdder > clinitAdders ;
73
75
74
76
/**
75
77
* When code generation requires holding a value in a class level field, this
@@ -83,13 +85,20 @@ public class CodeFlow implements Opcodes {
83
85
*/
84
86
private int nextFreeVariableId = 1 ;
85
87
86
- public CodeFlow (String clazzName , ClassWriter cw ) {
87
- this .compilationScopes = new Stack <>();
88
- this .compilationScopes .add (new ArrayList <>());
89
- this .cw = cw ;
90
- this .clazzName = clazzName ;
88
+
89
+ /**
90
+ * Construct a new {@code CodeFlow} for the given class.
91
+ * @param className the name of the class
92
+ * @param classWriter the corresponding ASM {@code ClassWriter}
93
+ */
94
+ public CodeFlow (String className , ClassWriter classWriter ) {
95
+ this .className = className ;
96
+ this .classWriter = classWriter ;
97
+ this .compilationScopes = new Stack <ArrayList <String >>();
98
+ this .compilationScopes .add (new ArrayList <String >());
91
99
}
92
100
101
+
93
102
/**
94
103
* Push the byte code to load the target (i.e. what was passed as the first argument
95
104
* to CompiledExpression.getValue(target, context))
@@ -103,6 +112,7 @@ public void loadTarget(MethodVisitor mv) {
103
112
* Push the bytecode to load the EvaluationContext (the second parameter passed to
104
113
* the compiled expression method).
105
114
* @param mv the visitor into which the load instruction should be inserted
115
+ * @since 4.3.4
106
116
*/
107
117
public void loadEvaluationContext (MethodVisitor mv ) {
108
118
mv .visitVarInsn (ALOAD , 2 );
@@ -164,18 +174,18 @@ public void unboxBooleanIfNecessary(MethodVisitor mv) {
164
174
public void finish () {
165
175
if (this .fieldAdders != null ) {
166
176
for (FieldAdder fieldAdder : this .fieldAdders ) {
167
- fieldAdder .generateField (cw , this );
177
+ fieldAdder .generateField (this . classWriter , this );
168
178
}
169
179
}
170
180
if (this .clinitAdders != null ) {
171
- MethodVisitor mv = cw .visitMethod (ACC_PUBLIC | ACC_STATIC , "<clinit>" , "()V" , null , null );
181
+ MethodVisitor mv = this . classWriter .visitMethod (ACC_PUBLIC | ACC_STATIC , "<clinit>" , "()V" , null , null );
172
182
mv .visitCode ();
173
- this .nextFreeVariableId = 0 ; // To 0 because there is no 'this' in a clinit
183
+ this .nextFreeVariableId = 0 ; // to 0 because there is no 'this' in a clinit
174
184
for (ClinitAdder clinitAdder : this .clinitAdders ) {
175
185
clinitAdder .generateCode (mv , this );
176
186
}
177
187
mv .visitInsn (RETURN );
178
- mv .visitMaxs (0 ,0 ); // not supplied due to COMPUTE_MAXS
188
+ mv .visitMaxs (0 ,0 ); // not supplied due to COMPUTE_MAXS
179
189
mv .visitEnd ();
180
190
}
181
191
}
@@ -213,13 +223,13 @@ public int nextFreeVariableId() {
213
223
}
214
224
215
225
public String getClassName () {
216
- return this .clazzName ;
226
+ return this .className ;
217
227
}
218
228
219
229
220
230
/**
221
231
* Insert any necessary cast and value call to convert from a boxed type to a
222
- * primitive value
232
+ * primitive value.
223
233
* @param mv the method visitor into which instructions should be inserted
224
234
* @param ch the primitive type desired as output
225
235
* @param stackDescriptor the descriptor of the type on top of the stack
0 commit comments