public class CodeFlow extends Object implements Opcodes
Records intermediate compilation state as the bytecode is generated. Also includes various bytecode generation helper functions.
Modifier and Type | Class and Description |
---|---|
static interface |
CodeFlow.ClinitAdder
Interface used to generate
clinit static initializer blocks. |
static interface |
CodeFlow.FieldAdder
Interface used to generate fields.
|
AALOAD, AASTORE, ACC_ABSTRACT, ACC_ANNOTATION, ACC_BRIDGE, ACC_DEPRECATED, ACC_ENUM, ACC_FINAL, ACC_INTERFACE, ACC_MANDATED, ACC_MODULE, ACC_NATIVE, ACC_OPEN, ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC, ACC_RECORD, ACC_STATIC, ACC_STATIC_PHASE, ACC_STRICT, ACC_SUPER, ACC_SYNCHRONIZED, ACC_SYNTHETIC, ACC_TRANSIENT, ACC_TRANSITIVE, ACC_VARARGS, ACC_VOLATILE, ACONST_NULL, ALOAD, ANEWARRAY, ARETURN, ARRAYLENGTH, ASM10_EXPERIMENTAL, ASM4, ASM5, ASM6, ASM7, ASM8, ASM9, ASTORE, ATHROW, BALOAD, BASTORE, BIPUSH, CALOAD, CASTORE, CHECKCAST, D2F, D2I, D2L, DADD, DALOAD, DASTORE, DCMPG, DCMPL, DCONST_0, DCONST_1, DDIV, DLOAD, DMUL, DNEG, DOUBLE, DREM, DRETURN, DSTORE, DSUB, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, F_APPEND, F_CHOP, F_FULL, F_NEW, F_SAME, F_SAME1, F2D, F2I, F2L, FADD, FALOAD, FASTORE, FCMPG, FCMPL, FCONST_0, FCONST_1, FCONST_2, FDIV, FLOAD, FLOAT, FMUL, FNEG, FREM, FRETURN, FSTORE, FSUB, GETFIELD, GETSTATIC, GOTO, H_GETFIELD, H_GETSTATIC, H_INVOKEINTERFACE, H_INVOKESPECIAL, H_INVOKESTATIC, H_INVOKEVIRTUAL, H_NEWINVOKESPECIAL, H_PUTFIELD, H_PUTSTATIC, I2B, I2C, I2D, I2F, I2L, I2S, IADD, IALOAD, IAND, IASTORE, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5, ICONST_M1, IDIV, IF_ACMPEQ, IF_ACMPNE, IF_ICMPEQ, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ICMPLT, IF_ICMPNE, IFEQ, IFGE, IFGT, IFLE, IFLT, IFNE, IFNONNULL, IFNULL, IINC, ILOAD, IMUL, INEG, INSTANCEOF, INTEGER, INVOKEDYNAMIC, INVOKEINTERFACE, INVOKESPECIAL, INVOKESTATIC, INVOKEVIRTUAL, IOR, IREM, IRETURN, ISHL, ISHR, ISTORE, ISUB, IUSHR, IXOR, JSR, L2D, L2F, L2I, LADD, LALOAD, LAND, LASTORE, LCMP, LCONST_0, LCONST_1, LDC, LDIV, LLOAD, LMUL, LNEG, LONG, LOOKUPSWITCH, LOR, LREM, LRETURN, LSHL, LSHR, LSTORE, LSUB, LUSHR, LXOR, MONITORENTER, MONITOREXIT, MULTIANEWARRAY, NEW, NEWARRAY, NOP, NULL, POP, POP2, PUTFIELD, PUTSTATIC, RET, RETURN, SALOAD, SASTORE, SIPUSH, SOURCE_DEPRECATED, SOURCE_MASK, SWAP, T_BOOLEAN, T_BYTE, T_CHAR, T_DOUBLE, T_FLOAT, T_INT, T_LONG, T_SHORT, TABLESWITCH, TOP, UNINITIALIZED_THIS, V_PREVIEW, V1_1, V1_2, V1_3, V1_4, V1_5, V1_6, V1_7, V1_8, V10, V11, V12, V13, V14, V15, V16, V17, V18, V9
Constructor and Description |
---|
CodeFlow(String className,
ClassWriter classWriter)
Construct a new
CodeFlow for the given class. |
Modifier and Type | Method and Description |
---|---|
static boolean |
areBoxingCompatible(String desc1,
String desc2)
Determine whether boxing/unboxing can get from one type to the other.
|
static int |
arrayCodeFor(String arraytype)
Determine the appropriate T tag to use for the NEWARRAY bytecode.
|
static String |
createSignatureDescriptor(Constructor<?> ctor)
Create the JVM signature descriptor for a constructor.
|
static String |
createSignatureDescriptor(Method method)
Create the JVM signature descriptor for a method.
|
void |
enterCompilationScope()
Enter a new compilation scope, usually due to nested expression evaluation.
|
void |
exitCompilationScope()
Exit a compilation scope, usually after a nested expression has been evaluated.
|
void |
finish()
Called after the main expression evaluation method has been generated, this
method will callback any registered FieldAdders or ClinitAdders to add any
extra information to the class representing the compiled expression.
|
String |
getClassName() |
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.
|
static void |
insertArrayStore(MethodVisitor mv,
String arrayElementType)
Produce appropriate bytecode to store a stack item in an array.
|
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.
|
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.
|
static void |
insertCheckCast(MethodVisitor mv,
String descriptor)
Insert the appropriate CHECKCAST instruction for the supplied descriptor.
|
static void |
insertNewArrayCode(MethodVisitor mv,
int size,
String arraytype)
Produce the correct bytecode to build an array.
|
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.
|
static void |
insertOptimalLoad(MethodVisitor mv,
int value)
Create the optimal instruction for loading a number on the stack.
|
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.
|
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.
|
static boolean |
isBooleanCompatible(String descriptor)
Determine whether the descriptor is for a boolean primitive or boolean reference type.
|
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.
|
static boolean |
isPrimitive(String descriptor)
Determine whether the descriptor is for a primitive type.
|
static boolean |
isPrimitiveArray(String descriptor)
Determine whether the descriptor is for a primitive array (e.g.
|
static boolean |
isPrimitiveOrUnboxableSupportedNumber(String descriptor)
Determine if the supplied descriptor is for a supported number.
|
static boolean |
isPrimitiveOrUnboxableSupportedNumberOrBoolean(String descriptor)
Determine if the supplied descriptor is for a supported number type or boolean.
|
static boolean |
isReferenceTypeArray(String arraytype)
Return if the supplied array type has a core component reference type.
|
String |
lastDescriptor()
Return the descriptor for the item currently on top of the stack (in the current scope).
|
void |
loadEvaluationContext(MethodVisitor mv)
Push the bytecode to load the EvaluationContext (the second parameter passed to
the compiled expression method).
|
void |
loadTarget(MethodVisitor mv)
Push the byte code to load the target (i.e.
|
int |
nextFieldId() |
int |
nextFreeVariableId() |
void |
pushDescriptor(String descriptor)
Record the descriptor for the most recently evaluated expression element.
|
void |
registerNewClinit(CodeFlow.ClinitAdder clinitAdder)
Register a ClinitAdder which will add code to the static
initializer in the generated class to support the code
produced by an ast nodes primary generateCode() method.
|
void |
registerNewField(CodeFlow.FieldAdder fieldAdder)
Register a FieldAdder which will add a new field to the generated
class to support the code produced by an ast nodes primary
generateCode() method.
|
static String |
toBoxedDescriptor(String primitiveDescriptor) |
static String |
toDescriptor(Class<?> type)
Deduce the descriptor for a type.
|
static String |
toDescriptorFromObject(Object value)
Determine the descriptor for an object instance (or
null ). |
static String[] |
toDescriptors(Class<?>[] types)
Create an array of descriptors from an array of classes.
|
static String |
toJvmDescriptor(Class<?> clazz)
Determine the JVM descriptor for a specified class.
|
static String[] |
toParamDescriptors(Constructor<?> ctor)
Create an array of descriptors representing the parameter types for the supplied
constructor.
|
static String[] |
toParamDescriptors(Method method)
Create an array of descriptors representing the parameter types for the supplied
method.
|
static char |
toPrimitiveTargetDesc(String descriptor)
Convert a type descriptor to the single character primitive descriptor.
|
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.
|
public CodeFlow(String className, ClassWriter classWriter)
CodeFlow
for the given class.className
- the name of the classclassWriter
- the corresponding ASM ClassWriter
public void loadTarget(MethodVisitor mv)
mv
- the visitor into which the load instruction should be insertedpublic void loadEvaluationContext(MethodVisitor mv)
mv
- the visitor into which the load instruction should be insertedpublic void pushDescriptor(@Nullable String descriptor)
descriptor
- type descriptor for most recently evaluated elementpublic void enterCompilationScope()
public void exitCompilationScope()
@Nullable public String lastDescriptor()
public void unboxBooleanIfNecessary(MethodVisitor mv)
mv
- the visitor into which new instructions should be insertedpublic void finish()
public void registerNewField(CodeFlow.FieldAdder fieldAdder)
public void registerNewClinit(CodeFlow.ClinitAdder clinitAdder)
public int nextFieldId()
public int nextFreeVariableId()
public String getClassName()
public static void insertUnboxInsns(MethodVisitor mv, char ch, @Nullable String stackDescriptor)
mv
- the method visitor into which instructions should be insertedch
- the primitive type desired as outputstackDescriptor
- the descriptor of the type on top of the stackpublic static void insertUnboxNumberInsns(MethodVisitor mv, char targetDescriptor, @Nullable String stackDescriptor)
mv
- the method visitor into which instructions should be insertedtargetDescriptor
- the primitive type desired as outputstackDescriptor
- the descriptor of the type on top of the stackpublic static void insertAnyNecessaryTypeConversionBytecodes(MethodVisitor mv, char targetDescriptor, String stackDescriptor)
mv
- the method visitor into which instructions should be placedtargetDescriptor
- the (primitive) descriptor of the target typestackDescriptor
- the descriptor of the operand on top of the stackpublic static String createSignatureDescriptor(Method method)
method
- the methodpublic static String createSignatureDescriptor(Constructor<?> ctor)
ctor
- the constructorpublic static String toJvmDescriptor(Class<?> clazz)
clazz
- a classpublic static String toDescriptorFromObject(@Nullable Object value)
null
).value
- an object (possibly null
)null
value)public static boolean isBooleanCompatible(@Nullable String descriptor)
descriptor
- type descriptortrue
if the descriptor is boolean compatiblepublic static boolean isPrimitive(@Nullable String descriptor)
descriptor
- type descriptortrue
if a primitive typepublic static boolean isPrimitiveArray(@Nullable String descriptor)
descriptor
- the descriptor for a possible primitive arraytrue
if the descriptor a primitive arraypublic static boolean areBoxingCompatible(String desc1, String desc2)
true
if it is possible to get (via boxing) from one descriptor to the otherpublic static boolean isPrimitiveOrUnboxableSupportedNumberOrBoolean(@Nullable String descriptor)
descriptor
- the descriptor for a typetrue
if the descriptor is for a supported numeric type or booleanpublic static boolean isPrimitiveOrUnboxableSupportedNumber(@Nullable String descriptor)
descriptor
- the descriptor for a typetrue
if the descriptor is for a supported numeric typepublic static boolean isIntegerForNumericOp(Number number)
public static char toPrimitiveTargetDesc(String descriptor)
descriptor
- a descriptor for a type that should have a primitive representationpublic static void insertCheckCast(MethodVisitor mv, @Nullable String descriptor)
mv
- the target visitor into which the instruction should be inserteddescriptor
- the descriptor of the type to cast topublic static void insertBoxIfNecessary(MethodVisitor mv, @Nullable String descriptor)
mv
- the target visitor for the new instructionsdescriptor
- the descriptor of a type that may or may not need boxingpublic static void insertBoxIfNecessary(MethodVisitor mv, char ch)
mv
- the target visitor for the new instructionsch
- the descriptor of the type that might need boxingpublic static String toDescriptor(Class<?> type)
type
- the type (may be primitive) for which to determine the descriptorpublic static String[] toParamDescriptors(Method method)
method
- a Methodpublic static String[] toParamDescriptors(Constructor<?> ctor)
ctor
- a Constructorpublic static String[] toDescriptors(Class<?>[] types)
types
- the input array of classespublic static void insertOptimalLoad(MethodVisitor mv, int value)
mv
- where to insert the bytecodevalue
- the value to be loadedpublic static void insertArrayStore(MethodVisitor mv, String arrayElementType)
mv
- where to insert the bytecodearrayElementType
- the type of the array elementspublic static int arrayCodeFor(String arraytype)
arraytype
- the array primitive component typepublic static boolean isReferenceTypeArray(String arraytype)
public static void insertNewArrayCode(MethodVisitor mv, int size, String arraytype)
mv
- the methodvisitor into which code should be insertedsize
- the size of the arrayarraytype
- the type of the arraypublic static void insertNumericUnboxOrPrimitiveTypeCoercion(MethodVisitor mv, @Nullable String stackDescriptor, char targetDescriptor)
For example, from a Integer to a double, just need to call 'Number.doubleValue()' but from an int to a double, need to use the bytecode 'i2d'.
mv
- the method visitor when instructions should be appendedstackDescriptor
- a descriptor of the operand on the stacktargetDescriptor
- a primitive type descriptor