|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: INNER | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object | +--gnu.jel.ExpressionImage
This class is responsible for generating valid Java class files based on a sequence of calls to it's methods (asm_XXXX family of methods). This assembler tries to do more things than other java assemblers do. It keeps track of types in Java stack and automatically chooses which java bytecodes should be generated to perform a given operation on types in stack.
Anyway, it is not general purpose Java assembler, it is specifically JEL oriented. Currently this assembler does not provide direct access to Java control transfer instructions.
This class is designed to be the part of a bigger package. This means it will silently generate wrong bytecodes. ;) BUT, if You compile it with debugging ON (see boolean gnu.jel.debug.Debug.enabled) it should warn You about all possible wrong things it does. If there are more assertions to be made, please submit Your patches to metlov@fzu.cz.
Debug.enabled
Field Summary | |
static int |
BI_AN
Denotes the AND binary operation. |
static int |
BI_DI
Denotes the DIVIDE binary operation. |
static int |
BI_EQ
Denotes binary comparizon for equality |
static int |
BI_GE
Denotes binary comparizon for "greater or equal" |
static int |
BI_GT
Denotes binary comparizon for "greater" |
static int |
BI_LE
Denotes binary comparizon for "less or equal" |
static int |
BI_LS
Denotes binary left shift |
static int |
BI_LT
Denotes binary comparizon for "less" |
static int |
BI_MI
Denotes the MINUS binary operation. |
static int |
BI_MU
Denotes the MULTIPLY binary operation. |
static int |
BI_NE
Denotes binary comparizon for inequality |
static int |
BI_OR
Denotes the OR binary operation. |
static int |
BI_PL
Denotes the PLUS binary operation. |
static int |
BI_RE
Denotes the REMAINDER binary operation. |
static int |
BI_RSS
Denotes binary right signed shift |
static int |
BI_RUS
Denotes binary right unsigned shift |
static int |
BI_XO
Denotes the XOR binary operation. |
static java.lang.String[] |
binaryNames
Names of binary operations by ID in the readable form. |
static java.lang.String[] |
binarySymbols
Symbols of binary operations by ID in the readable form. |
static int |
LOG_AN
Denotes logical conjunction operator |
static int |
LOG_NO
Denotes logical complement operator |
static int |
LOG_OR
Denotes logical disjunction operator |
static java.lang.String[] |
logicalNames
Names of logical operations by ID in the readable form. |
static java.lang.String[] |
logicalSymbols
Symbols of logical operations by ID in the readable form. |
static java.lang.String[] |
primitiveTypeNames
Names of the primitive types by ID in readable form. |
static java.lang.Class[] |
primitiveTypes
Classes of the primitive types by ID |
static int |
UN_NE
Denotes the unary NEGATION operation. |
static int |
UN_NO
Denotes the unary bitwise complement operation. |
static java.lang.String[] |
unaryNames
Names of unary operations by ID in the readable form. |
static java.lang.String[] |
unarySymbols
Symbols of unary operations by ID in the readable form. |
Constructor Summary | |
ExpressionImage()
Constructs and initializes empty expression image. |
Method Summary | |
void |
asm_binary_param(int opc)
Denotes that the first parameter for the given binary OP is now in stack. |
void |
asm_binary(int o)
Generates code to perform given binary operation. |
void |
asm_branch_end()
Finishes generation of code for conditional. |
void |
asm_branch_start_false()
Continues generation of code for conditional. |
void |
asm_branch_start_true()
Starts generation of code for conditional. |
boolean |
asm_convert(java.lang.Class type)
Converts current top of the java stack to the given class type. |
void |
asm_func_call()
Finishes generation of call to a function. |
void |
asm_func_param()
Denotes that the next parameter for the current function is now in stack. |
void |
asm_func_start(java.lang.reflect.Method f,
int id)
Starts generation of code for the method call. |
void |
asm_get_array_element()
Generates code for loading an element from the array. |
void |
asm_load_field(java.lang.reflect.Field f,
int id)
Generates code for loading of a field value to the stack. |
void |
asm_load_object(java.lang.Object o)
Generates code to load given object constant into Java stack. |
void |
asm_load_primitive(java.lang.Object o)
Generates code to load given constant of a primitive type. |
void |
asm_logical_binary_param(int opc)
Denotes the first parameter for the given logical binary OP is now in stack. |
void |
asm_logical_binary(int opc)
Generates code to perform given logical binary operation. |
void |
asm_logical_block()
This function starts a group of logical subexpressions. |
void |
asm_logical_unblock_not()
This function finishes a group of logical subexpressions with inversion. |
void |
asm_return()
Finishes construction of expression by generating code to return a value. |
void |
asm_throw_return()
Finishes construction of expression by generating code to throw exception. |
void |
asm_unary(int o)
Generates code to perform given unary operation on the value in stack. |
static boolean |
canConvert(java.lang.Class t1,
java.lang.Class t2)
Tests is this assembler can generate code to convert from from one type to another even with possible loss of the information. |
static boolean |
canConvertByWidening(java.lang.Class t1,
java.lang.Class t2)
Tests is this assembler can generate code to convert from from one type to another without loss of the information. |
static boolean |
canGenerateBinary(int op,
java.lang.Class t1,
java.lang.Class t2)
Used to test if this assembler can generate given binary operation. |
static boolean |
canGenerateUnary(int op,
java.lang.Class type)
Used to test if this assembler can generate given unary operation. |
static java.lang.Class |
getBinaryPromoted(java.lang.Class c1,
java.lang.Class c2)
Performs binary numeric promotion of types. |
ExpressionBits |
getBits()
Returns compiled expression represented by ExpressionBits object. |
CompiledExpression |
getExpression()
Constructs a new instance of this expression. |
byte[] |
getImage()
Used to get the binary image of the class. |
static java.lang.String |
getSignature(java.lang.Class cls)
Computes the signature of the given class. |
static java.lang.String |
getSignature(java.lang.reflect.Constructor c)
Computes signature of the given constructor. |
static java.lang.String |
getSignature(java.lang.reflect.Method m)
Computes signature of the given method. |
static java.lang.Class |
getUnaryPromoted(java.lang.Class c)
Performs unary numeric promotion of types. |
static boolean |
isPromotionBinary(int binary_op)
Checks if the binary numeric promotion is required for the operation. |
static void |
main(java.lang.String[] args)
Performs unitary test of the code generator. |
static void |
test(Tester t)
Performs unitary test of the code generator. |
Methods inherited from class java.lang.Object |
clone,
equals,
finalize,
getClass,
hashCode,
notify,
notifyAll,
toString,
wait,
wait,
wait |
Field Detail |
public static final int BI_PL
public static final int BI_MI
public static final int BI_MU
public static final int BI_DI
public static final int BI_RE
public static final int BI_AN
public static final int BI_OR
public static final int BI_XO
public static final int BI_EQ
public static final int BI_NE
public static final int BI_LT
public static final int BI_GE
public static final int BI_GT
public static final int BI_LE
public static final int BI_LS
public static final int BI_RSS
public static final int BI_RUS
public static final java.lang.String[] binaryNames
public static final java.lang.String[] binarySymbols
public static final int LOG_AN
public static final int LOG_OR
public static final int LOG_NO
public static final java.lang.String[] logicalNames
public static final java.lang.String[] logicalSymbols
public static final int UN_NE
public static final int UN_NO
public static final java.lang.String[] unaryNames
public static final java.lang.String[] unarySymbols
public static final java.lang.Class[] primitiveTypes
public static final java.lang.String[] primitiveTypeNames
Constructor Detail |
public ExpressionImage()
Immediately after the construction of the expression a number of code generating methods can be issued:
asm_load_primitive(...) asm_binary_param(..) ...
The code generation should be finished by one of the return methods:
asm_return(); asm_throw_return();
Before any return method is called, the code generation is assumed to be in progress and methods, attempting to get class representation (getImage) or instantiate the class (getExpression) will fail assertion.
After the code generation is finished and one of return methods is called methods, attempting to modify the class (i.e. asm_load_primitive(...)...) will fail. This is done to ensure integrity of generated classes.
Constants of the type object are allowed in the generated expressions. (If You don't know in java the constants are residing in the constant pool and it is impossible to store constants of general Object type other than java.lang.String there. This assembler overcomes this limitation and allows to use other _NON-MUTABLE_ objects as constants. More information is provided in the description of asm_load_object method.
asm_load_object(java.lang.Object)
,
asm_load_primitive(java.lang.Object)
,
asm_binary(int)
,
asm_convert(java.lang.Class)
,
asm_func_call()
,
asm_logical_binary(int)
,
asm_logical_unblock_not()
,
asm_unary(int)
,
asm_return()
,
asm_throw_return()
Method Detail |
public static final boolean isPromotionBinary(int binary_op)
Used to check whether given binary operation requires binary or unary numeric promotion (see JLS 5.6.1) of it's operands.
binary_op
- is one of BI_XXX constants.public static java.lang.String getSignature(java.lang.reflect.Method m)
The signature of the method(Method descriptor) is the string and it's format is described in the paragraph 4.3.3 of the Java VM specification (ISBN 0-201-63451-1).
This utility method can be used outside of the JEL package it does not involve any JEL specific assumptions and should follow JVM Specification precisely.
m
- is the method to compute the sugnature of.public static java.lang.String getSignature(java.lang.reflect.Constructor c)
m
- is the method to compute the sugnature of.getSignature(java.lang.reflect.Method)
public static java.lang.String getSignature(java.lang.Class cls)
The signature of the class (Field descriptor) is the string and it's format is described in the paragraph 4.3.2 of the Java VM specification (ISBN 0-201-63451-1).
The same can be done using java.lang.Class.getName() by converting it's result into the "historical form".
This utility method can be used outside of the JEL package it does not involve any JEL specific assumptions and should follow JVM Specification precisely.
cls
- is the class to compute the sgnature of. Can be primitive or
array type.public ExpressionBits getBits()
This function should be called after the code generation had finished.
The only case You'll want to get gnu.jel.ExpressionBits class instead of instantiated and ready to run gnu.jel.CompiledExpression subclass is when You intend to write expression to a persistent storage and run it in other JVM session.
public byte[] getImage()
This function returns bytecode of generated expression in a Java classfile format. It is for debugging purposes only. Use ExpressionBits if You want to store expression into a stream (file).
public CompiledExpression getExpression()
This function returns ready to run instance of gnu.jel.CompiledExpression subclass.
public void asm_load_object(java.lang.Object o)
Constants of type object, other than instances of java.lang.String are not directly supported by Java Virtual Machine. This means there is no way to reinstantiate those object based on the information in the Java class file alone.
To overcome this limitation an array of such objects is created and only integer index into this "object constants" array is compiled into a class file. The drawback is that the generated class file can not be run without proper object constants array supplied. This means bytecode alone does not represent compiled program anymore.
To simplify storage of expressions an ExpressionBits class is introduced which holds both bytecode and object constants, allowing to easily store them together in a stream.
CONCLUSION : if Your class uses this function for objects other than Strings You _must_ use ExpressionBits to store compiled bytecode.
o
- is the object to load.ExpressionBits
public void asm_load_primitive(java.lang.Object o)
For example, to load double constant 1.0D into
the Java stack one has to call :
asm_load_primitive(new Double(1.0)).
o
- is the value of a constant of primitive type, wrapped into
corresponding reflection object.public static boolean canConvert(java.lang.Class t1, java.lang.Class t2)
Both widening and narrowing conversions are supported by the assembler, this function reports all supported conversions.
There are thoughts about support wrapping/unwrapping conversions (i.e. double <--> java.lang.Double) as described in the Java Reflection Specification. Currently these are not supported.
t1
- is the type You want to convert from.t2
- is the type You want to convert to.public static boolean canConvertByWidening(java.lang.Class t1, java.lang.Class t2)
Both widening and narrowing conversions are supported by the assembler itself, this function reports widening conversions only.
t1
- is the type You want to convert from.t2
- is the type You want to convert to.public boolean asm_convert(java.lang.Class type)
type
- is the type to convert to, can be primitive.public static java.lang.Class getBinaryPromoted(java.lang.Class c1, java.lang.Class c2)
Promotion is done according to the Java Language Specification (paragraph 5.6.2). Both parameters should be Java primitive types.
c1
- first typec2
- second typepublic static java.lang.Class getUnaryPromoted(java.lang.Class c)
Promotion is done according to the Java Language Specification (paragraph 5.6.1). Both parameters should be Java primitive numeric types.
c
- the type to promotepublic static boolean canGenerateUnary(int op, java.lang.Class type)
is
- the code of operation (UN_NE).type
- is the type of the operand.public void asm_unary(int o)
Unary operations can be performed on the primitive Java types only.
If operation can not be supported for the given type this method returns false and generates nothing.
o
- type of operation to perform, one of NEpublic static boolean canGenerateBinary(int op, java.lang.Class t1, java.lang.Class t2)
is
- the code of operation (BI_PL,BI_MI,BI_MU ...).t1
- is the type of the first operand.t2
- is the type of the second operand.public void asm_binary(int o)
Method canGenerateBinary(..) should be used to determine if the binary operation can be generated for particular types of data.
The pattern to generate binary operations with this code generator is following :
1. Calculate the first operand. 2. asm_binary_param( BI_XXX ) 3. Calculate the second operand. 4. asm_binary( BI_XXX )
If operation can not be supported due to incompatible types of operands this method returns false and generates nothing.
o
- type of operation to perform, one of BI_XXXcanGenerateBinary(int, java.lang.Class, java.lang.Class)
,
asm_binary_param(int)
public void asm_func_start(java.lang.reflect.Method f, int id)
Method can be static or virtual. See the descrition of asm_func_call for more details.
f
- is the method to call.id
- is the number of the function in the array of the
instances of objects implementing the function (for virtual
methods only).asm_func_call()
public void asm_func_param()
Actually, this method generates code to convert the value currently on top of Java stack to the next formal parameter type of a current function.
asm_func_start(java.lang.reflect.Method, int)
public void asm_func_call()
Call to this method should be followed zero or more asm_func_param() calls which would transform parameters on top of the stack to be compatible with the function input (each additioal call will process the next formal parameter).
The pattern to generate the function call is the following
1. asm_func_start(...); 2. Calculate the first parameter. 3. asm_func_param(); 4. Calculate the second parameter. 5. asm_func_param(); .... so on ... 6 Calculate the last parameter. 7. asm_func_param(); 8. asm_func_call();
Correctness of id parameter can not be checked by the code generator !!! Be careful, runtime error will be generated if it's incorrect.
asm_func_param()
,
asm_func_start(java.lang.reflect.Method, int)
public void asm_load_field(java.lang.reflect.Field f, int id)
f
- is the method to call.id
- is the number of the object in the array of "this" references,
used for non-static fields only.asm_func_call()
public void asm_get_array_element()
the array pointer and the in index of element must be already at stack
public void asm_branch_start_true()
Starts the branch, corresponding to the case when previous logical was "true". expression.
The pattern to generate an "if" operator or ?: conditional is the following :
1. Calculate condition 2. asm_branch_start_true() 3. Generate code for the "true" branch 4. asm_branch_start_false() 5. Generate code for the "false" branch 6. asm_branch_end()
Note that the code for "true" branch should be generated BEFORE the code for the current branch. This limitation may be removed in a future.
public void asm_branch_start_false()
asm_branch_start_true()
public void asm_branch_end()
asm_branch_start_true()
public void asm_binary_param(int opc)
op
- type of operation to perform, one of BI_XXXasm_binary(int)
public void asm_logical_binary_param(int opc)
opc
- is the code of the logical binary operation (LOG_AN,LOG_OR)asm_logical_binary(int)
public void asm_logical_binary(int opc)
The logical binary operations are either logical and (LOG_AN) or logical or (LOG_OR).
The following pattern should be followed in order to evaluate logical expressions :
1. Calculate the first operand (should be boolean). 2. asm_logical_binary_param(| ) 3. Calculate the second operand (should be boolean). 4. asm_logical_binary( | )
opc
- is the code of the logical binary operation (LOG_AN,LOG_OR)public void asm_logical_block()
asm_logical_unblock_not()
public void asm_logical_unblock_not()
For example, to calculate "!(..something..)" it is needed to call :
asm_logical_block() .... calculate something manipulating with other methods of this code generator .... asm_logical_unblock_not();
After the above block the state of this codegenerator will correspond to the boolean result of the logical not operator on something.
public void asm_return()
Code to return to a caller a quantity on top of the Java stack is generated.
public void asm_throw_return()
Object on top of the Java stack (which should be instance of java.lang.Throwable) is thrown.
public static void main(java.lang.String[] args)
args
- ignored.public static void test(Tester t)
Used if all package is being tested and not just codegen.
t
- Tester to report test results.
|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: INNER | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |