Records intermediate compilation state as the bytecode is generated. Also includes various bytecode generation helper functions.
| Modifier and Type | Class and Description |
|---|---|
| public static interface | CodeFlow.ClinitAdder
Interface used to generate |
| public static interface | CodeFlow.FieldAdder
Interface used to generate fields. |
| Modifier and Type | Field and Description |
|---|---|
| private final String | className
Name of the class being generated. |
| private final ClassWriter | classWriter
The current class being generated. |
| private List | clinitAdders
As SpEL AST nodes are called to generate code for the main evaluation method they can register to add code to a static initializer in the class. |
| private final Deque | compilationScopes
Record the type of what is on top of the bytecode stack (i.e. the type of the output from the previous expression component). |
| private List | fieldAdders
As SpEL AST nodes are called to generate code for the main evaluation method they can register to add a field to this class. |
| private int | nextFieldId
When code generation requires holding a value in a class level field, this is used to track the next available field id (used as a name suffix). |
| private int | nextFreeVariableId
When code generation requires an intermediate variable within a method, this method records the next available variable (variable 0 is 'this'). |
| Access | Constructor and Description |
|---|---|
| public | CodeFlow(String
the name of the class className, ClassWriter the corresponding ASM classWriter)ClassWriterConstruct a new |
| Modifier and Type | Method and Description |
|---|---|
| public static boolean | Returns: true if it is possible to get (via boxing) from one descriptor to the otherDetermine whether boxing/unboxing can get from one type to the other. |
| public static int | Returns: the T tag to use for NEWARRAYthe array primitive component type arrayType)Determine the appropriate T tag to use for the NEWARRAY bytecode. |
| private static boolean | |
| public static String | Returns: a String signature descriptor (e.g. "(ILjava/lang/String;)V")the method method)Create the JVM signature descriptor for a method. |
| public static String | Returns: a String signature descriptor (e.g. "(ILjava/lang/String;)V")the constructor ctor)Create the JVM signature descriptor for a constructor. |
| public void | |
| public void | exitCompilationScope()
Exit a compilation scope, usually after a nested expression has been evaluated. |
| public void | finish()
Called after the main expression evaluation method has been generated, this method will call back any registered FieldAdders or ClinitAdders to add any extra information to the class representing the compiled expression. |
| public String | |
| public static void | insertAnyNecessaryTypeConversionBytecodes(MethodVisitor
the method visitor into which instructions should be placed mv, char the (primitive) descriptor of the target type targetDescriptor, String the descriptor of the operand on top of the stack stackDescriptor)Insert any necessary numeric conversion bytecodes based upon what is on the stack and the desired target type. |
| public static void | insertArrayStore(MethodVisitor
where to insert the bytecode mv, String the type of the array elements arrayElementType)Produce appropriate bytecode to store a stack item in an array. |
| public static void | insertBoxIfNecessary(MethodVisitor
the method visitor for the new instructions mv, String the descriptor of a type that may or may not need boxing descriptor)Determine the appropriate boxing instruction for a specific type (if it needs boxing) and insert the instruction into the supplied visitor. |
| public static void | insertBoxIfNecessary(MethodVisitor
the method visitor for the new instructions mv, char the descriptor of the type that might need boxing ch)Determine the appropriate boxing instruction for a specific type (if it needs boxing) and insert the instruction into the supplied visitor. |
| public static void | insertCheckCast(MethodVisitor
the method visitor into which the instruction should be inserted mv, String the descriptor of the type to cast to descriptor)Insert the appropriate CHECKCAST instruction for the supplied descriptor. |
| public static void | insertNewArrayCode(MethodVisitor
the method visitor into which code should be inserted mv, int the size of the array size, String the type of the array arrayType)Produce the correct bytecode to build an array. |
| public static void | insertNumericUnboxOrPrimitiveTypeCoercion(MethodVisitor
the method visitor when instructions should be appended mv, String a descriptor of the operand on the stack stackDescriptor, char a primitive type descriptor targetDescriptor)For use in mathematical operators, handles converting from a (possibly boxed) number on the stack to a primitive numeric type. |
| public static void | insertOptimalLoad(MethodVisitor
where to insert the bytecode mv, int the value to be loaded value)Create the optimal instruction for loading a number on the stack. |
| public static void | insertUnboxInsns(MethodVisitor
the method visitor into which instructions should be inserted mv, char the primitive type desired as output ch, String the descriptor of the type on top of the stack stackDescriptor)Insert any necessary cast and value call to convert from a boxed type to a primitive value. |
| public static void | insertUnboxNumberInsns(MethodVisitor
the method visitor into which instructions should be inserted mv, char the primitive type desired as output targetDescriptor, String the descriptor of the type on top of the stack stackDescriptor)For numbers, use the appropriate method on the number to convert it to the primitive type requested. |
| public static boolean | Returns: true if the descriptor is boolean compatibletype descriptor descriptor)Determine whether the descriptor is for a boolean primitive or boolean reference type. |
| public static boolean | isIntegerForNumericOp(Number
the number to check number)Determine whether the given number is to be considered as an integer for the purposes of a numeric operation at the bytecode level. |
| public static boolean | Returns: true if a primitive type or voidtype descriptor descriptor)Determine whether the descriptor is for a primitive type or |
| public static boolean | Returns: true if the descriptor a primitive arraythe descriptor for a possible primitive array descriptor)Determine whether the descriptor is for a primitive array (e.g. "[[I"). |
| public static boolean | Returns: true if the descriptor is for a supported numeric typethe descriptor for a type descriptor)Determine if the supplied descriptor is for a supported number. |
| public static boolean | Returns: true if the descriptor is for a supported numeric type or booleanthe descriptor for a type descriptor)Determine if the supplied descriptor is for a supported number type or boolean. |
| public static boolean | isReferenceTypeArray(String arrayType)
Return if the supplied array type has a core component reference type. |
| public String | lastDescriptor()
Return the descriptor for the item currently on top of the stack (in the current scope). |
| public void | loadEvaluationContext(MethodVisitor
the method visitor into which the load instruction should be inserted mv)Push the bytecode to load the EvaluationContext (the second parameter passed to the compiled expression method). |
| public void | loadTarget(MethodVisitor
the method visitor into which the load instruction should be inserted mv)Push the byte code to load the target (i.e. what was passed as the first argument to CompiledExpression.getValue(target, context)) |
| public int | |
| public int | |
| public void | pushDescriptor(String
type descriptor for most recently evaluated element descriptor)Record the descriptor for the most recently evaluated expression element. |
| public void | registerNewClinit(CodeFlow.
Register a ClinitAdder which will add code to the static initializer in the generated class to support the code produced by an AST node's primary generateCode() method. |
| public void | registerNewField(CodeFlow.
Register a FieldAdder which will add a new field to the generated class to support the code produced by an AST node's primary generateCode() method. |
| public static String | |
| public static String | Returns: the descriptorthe type (may be primitive) for which to determine the descriptor type)Deduce the descriptor for a type. |
| public static String | Returns: the type descriptor for the object (descriptor is "Ljava/lang/Object" fornull value)an object (possibly value)null)Determine the descriptor for an object instance (or |
| public static String[] | Returns: an array of descriptorsthe input array of classes types)Create an array of descriptors from an array of classes. |
| public static String | Returns: the JVM descriptor for the classa class clazz)Determine the JVM descriptor for a specified class. |
| public static String[] | Returns: a String array of descriptors, one entry for each method parametera Method method)Create an array of descriptors representing the parameter types for the supplied method. |
| public static String[] | Returns: a String array of descriptors, one entry for each constructor parametera Constructor ctor)Create an array of descriptors representing the parameter types for the supplied constructor. |
| public static char | Returns: the single character descriptor for a primitive input descriptora descriptor for a type that should have a primitive representation descriptor)Convert a type descriptor to the single character primitive descriptor. |
| public void | unboxBooleanIfNecessary(MethodVisitor
the method visitor into which new instructions should be inserted mv)If the codeflow shows the last expression evaluated to java.lang.Boolean then insert the necessary instructions to unbox that to a boolean primitive. |
| className | back to summary |
|---|---|
| private final String className Name of the class being generated. Typically used when generating code that accesses freshly generated fields on the generated type. | |
| classWriter | back to summary |
|---|---|
| private final ClassWriter classWriter The current class being generated. | |
| clinitAdders | back to summary |
|---|---|
| private List<CodeFlow. As SpEL AST nodes are called to generate code for the main evaluation method they can register to add code to a static initializer in the class. Any registered ClinitAdders will be called after the main evaluation function has finished being generated. | |
| compilationScopes | back to summary |
|---|---|
| private final Deque<List<String>> compilationScopes Record the type of what is on top of the bytecode stack (i.e. the type of the output from the previous expression component). New scopes are used to evaluate sub-expressions like the expressions for the argument values in a method invocation expression. | |
| fieldAdders | back to summary |
|---|---|
| private List<CodeFlow. As SpEL AST nodes are called to generate code for the main evaluation method they can register to add a field to this class. Any registered FieldAdders will be called after the main evaluation function has finished being generated. | |
| nextFieldId | back to summary |
|---|---|
| private int nextFieldId When code generation requires holding a value in a class level field, this is used to track the next available field id (used as a name suffix). | |
| nextFreeVariableId | back to summary |
|---|---|
| private int nextFreeVariableId When code generation requires an intermediate variable within a method, this method records the next available variable (variable 0 is 'this'). | |
| CodeFlow | back to summary |
|---|---|
| public CodeFlow(String className, ClassWriter classWriter) Construct a new
| |
| areBoxingCompatible | back to summary |
|---|---|
| public static boolean areBoxingCompatible(String desc1, String desc2) Determine whether boxing/unboxing can get from one type to the other. Assumes at least one of the types is in boxed form (i.e. single char descriptor).
| |
| arrayCodeFor | back to summary |
|---|---|
| public static int arrayCodeFor(String arrayType) Determine the appropriate T tag to use for the NEWARRAY bytecode.
| |
| checkPairs | back to summary |
|---|---|
| private static boolean checkPairs(String desc1, String desc2) | |
| createSignatureDescriptor | back to summary |
|---|---|
| public static String createSignatureDescriptor(Method method) Create the JVM signature descriptor for a method. This consists of the descriptors for the method parameters surrounded with parentheses, followed by the descriptor for the return type. Note the descriptors here are JVM descriptors, unlike the other descriptor forms the compiler is using which do not include the trailing semicolon. | |
| createSignatureDescriptor | back to summary |
|---|---|
| public static String createSignatureDescriptor(Constructor<?> ctor) Create the JVM signature descriptor for a constructor. This consists of the descriptors for the constructor parameters surrounded with parentheses, followed by the descriptor for the return type, which is always "V". Note the descriptors here are JVM descriptors, unlike the other descriptor forms the compiler is using which do not include the trailing semicolon.
| |
| enterCompilationScope | back to summary |
|---|---|
| public void enterCompilationScope() Enter a new compilation scope, usually due to nested expression evaluation. For example when the arguments for a method invocation expression are being evaluated, each argument will be evaluated in a new scope. | |
| exitCompilationScope | back to summary |
|---|---|
| public void exitCompilationScope() Exit a compilation scope, usually after a nested expression has been evaluated. For example after an argument for a method invocation has been evaluated this method returns us to the previous (outer) scope. | |
| finish | back to summary |
|---|---|
| public void finish() Called after the main expression evaluation method has been generated, this method will call back any registered FieldAdders or ClinitAdders to add any extra information to the class representing the compiled expression. | |
| getClassName | back to summary |
|---|---|
| public String getClassName() | |
| insertAnyNecessaryTypeConversionBytecodes | back to summary |
|---|---|
| public static void insertAnyNecessaryTypeConversionBytecodes(MethodVisitor mv, char targetDescriptor, String stackDescriptor) Insert any necessary numeric conversion bytecodes based upon what is on the stack and the desired target type.
| |
| insertArrayStore | back to summary |
|---|---|
| public static void insertArrayStore(MethodVisitor mv, String arrayElementType) Produce appropriate bytecode to store a stack item in an array. The instruction to use varies depending on whether the type is a primitive or reference type.
| |
| insertBoxIfNecessary | back to summary |
|---|---|
| public static void insertBoxIfNecessary(MethodVisitor mv, String descriptor) Determine the appropriate boxing instruction for a specific type (if it needs boxing) and insert the instruction into the supplied visitor.
| |
| insertBoxIfNecessary | back to summary |
|---|---|
| public static void insertBoxIfNecessary(MethodVisitor mv, char ch) Determine the appropriate boxing instruction for a specific type (if it needs boxing) and insert the instruction into the supplied visitor.
| |
| insertCheckCast | back to summary |
|---|---|
| public static void insertCheckCast(MethodVisitor mv, String descriptor) Insert the appropriate CHECKCAST instruction for the supplied descriptor.
| |
| insertNewArrayCode | back to summary |
|---|---|
| public static void insertNewArrayCode(MethodVisitor mv, int size, String arrayType) Produce the correct bytecode to build an array. The opcode to use and the signature to pass along with the opcode can vary depending on the signature of the array type.
| |
| insertNumericUnboxOrPrimitiveTypeCoercion | back to summary |
|---|---|
| public static void insertNumericUnboxOrPrimitiveTypeCoercion(MethodVisitor mv, String stackDescriptor, char targetDescriptor) For use in mathematical operators, handles converting from a (possibly boxed) number on the stack to a primitive numeric type. For example, from an Integer to a double, just need to call 'Number.doubleValue()' but from an int to a double, need to use the bytecode 'i2d'.
| |
| insertOptimalLoad | back to summary |
|---|---|
| public static void insertOptimalLoad(MethodVisitor mv, int value) Create the optimal instruction for loading a number on the stack.
| |
| insertUnboxInsns | back to summary |
|---|---|
| public static void insertUnboxInsns(MethodVisitor mv, char ch, String stackDescriptor) Insert any necessary cast and value call to convert from a boxed type to a primitive value.
| |
| insertUnboxNumberInsns | back to summary |
|---|---|
| public static void insertUnboxNumberInsns(MethodVisitor mv, char targetDescriptor, String stackDescriptor) For numbers, use the appropriate method on the number to convert it to the primitive type requested.
| |
| isBooleanCompatible | back to summary |
|---|---|
| public static boolean isBooleanCompatible(String descriptor) Determine whether the descriptor is for a boolean primitive or boolean reference type.
| |
| isIntegerForNumericOp | back to summary |
|---|---|
| public static boolean isIntegerForNumericOp(Number number) Determine whether the given number is to be considered as an integer for the purposes of a numeric operation at the bytecode level. | |
| isPrimitive | back to summary |
|---|---|
| public static boolean isPrimitive(String descriptor) Determine whether the descriptor is for a primitive type or
| |
| isPrimitiveArray | back to summary |
|---|---|
| public static boolean isPrimitiveArray(String descriptor) Determine whether the descriptor is for a primitive array (e.g. "[[I").
| |
| isPrimitiveOrUnboxableSupportedNumber | back to summary |
|---|---|
| public static boolean isPrimitiveOrUnboxableSupportedNumber(String descriptor) Determine if the supplied descriptor is for a supported number. The compilation process only (currently) supports certain number types. These are double, float, long and int.
| |
| isPrimitiveOrUnboxableSupportedNumberOrBoolean | back to summary |
|---|---|
| public static boolean isPrimitiveOrUnboxableSupportedNumberOrBoolean(String descriptor) Determine if the supplied descriptor is for a supported number type or boolean. The compilation process only (currently) supports certain number types. These are double, float, long and int.
| |
| isReferenceTypeArray | back to summary |
|---|---|
| public static boolean isReferenceTypeArray(String arrayType) Return if the supplied array type has a core component reference type. | |
| lastDescriptor | back to summary |
|---|---|
| public String lastDescriptor() Return the descriptor for the item currently on top of the stack (in the current scope).
| |
| loadEvaluationContext | back to summary |
|---|---|
| public void loadEvaluationContext(MethodVisitor mv) Push the bytecode to load the EvaluationContext (the second parameter passed to the compiled expression method).
| |
| loadTarget | back to summary |
|---|---|
| public void loadTarget(MethodVisitor mv) Push the byte code to load the target (i.e. what was passed as the first argument to CompiledExpression.getValue(target, context))
| |
| nextFieldId | back to summary |
|---|---|
| public int nextFieldId() | |
| nextFreeVariableId | back to summary |
|---|---|
| public int nextFreeVariableId() | |
| pushDescriptor | back to summary |
|---|---|
| public void pushDescriptor(String descriptor) Record the descriptor for the most recently evaluated expression element.
| |
| registerNewClinit | back to summary |
|---|---|
| public void registerNewClinit(CodeFlow. Register a ClinitAdder which will add code to the static initializer in the generated class to support the code produced by an AST node's primary generateCode() method. | |
| registerNewField | back to summary |
|---|---|
| public void registerNewField(CodeFlow. Register a FieldAdder which will add a new field to the generated class to support the code produced by an AST node's primary generateCode() method. | |
| toBoxedDescriptor | back to summary |
|---|---|
| public static String toBoxedDescriptor(String primitiveDescriptor) | |
| toDescriptor | back to summary |
|---|---|
| public static String toDescriptor(Class<?> type) Deduce the descriptor for a type. Descriptors are like JVM type names but missing the trailing ';' so for Object the descriptor is "Ljava/lang/Object" for int it is "I". | |
| toDescriptorFromObject | back to summary |
|---|---|
| public static String toDescriptorFromObject(Object value) Determine the descriptor for an object instance (or | |
| toDescriptors | back to summary |
|---|---|
| public static String[] toDescriptors(Class<?>[] types) Create an array of descriptors from an array of classes. | |
| toJvmDescriptor | back to summary |
|---|---|
| public static String toJvmDescriptor(Class<?> clazz) Determine the JVM descriptor for a specified class. Unlike the other descriptors used in the compilation process, this is the one the JVM wants, so this one includes any necessary trailing semicolon (e.g. Ljava/lang/String; rather than Ljava/lang/String) | |
| toParamDescriptors | back to summary |
|---|---|
| public static String[] toParamDescriptors(Method method) Create an array of descriptors representing the parameter types for the supplied method. Returns a zero sized array if there are no parameters. | |
| toParamDescriptors | back to summary |
|---|---|
| public static String[] toParamDescriptors(Constructor<?> ctor) Create an array of descriptors representing the parameter types for the supplied constructor. Returns a zero sized array if there are no parameters.
| |
| toPrimitiveTargetDesc | back to summary |
|---|---|
| public static char toPrimitiveTargetDesc(String descriptor) Convert a type descriptor to the single character primitive descriptor.
| |
| unboxBooleanIfNecessary | back to summary |
|---|---|
| public void unboxBooleanIfNecessary(MethodVisitor mv) If the codeflow shows the last expression evaluated to java.lang.Boolean then insert the necessary instructions to unbox that to a boolean primitive.
| |
clinit static initializer blocks.
| Modifier and Type | Method and Description |
|---|---|
| public void |
| generateCode | back to summary |
|---|---|
| public void generateCode(MethodVisitor mv, CodeFlow codeflow) | |
| Modifier and Type | Method and Description |
|---|---|
| public void |
| generateField | back to summary |
|---|---|
| public void generateField(ClassWriter cw, CodeFlow codeflow) | |