Class ClassGeneratorUtil
- java.lang.Object
-
- bsh.ClassGeneratorUtil
-
- All Implemented Interfaces:
bsh.org.objectweb.asm.Constants
public class ClassGeneratorUtil extends java.lang.Object implements bsh.org.objectweb.asm.Constants
ClassGeneratorUtil utilizes the ASM (www.objectweb.org) bytecode generator by Eric Bruneton in order to generate class "stubs" for BeanShell at runtime.Stub classes contain all of the fields of a BeanShell scripted class as well as two "callback" references to BeanShell namespaces: one for static methods and one for instance methods. Methods of the class are delegators which invoke corresponding methods on either the static or instance bsh object and then unpack and return the results. The static namespace utilizes a static import to delegate variable access to the class' static fields. The instance namespace utilizes a dynamic import (i.e. mixin) to delegate variable access to the class' instance variables.
Constructors for the class delegate to the static initInstance() method of ClassGeneratorUtil to initialize new instances of the object. initInstance() invokes the instance intializer code (init vars and instance blocks) and then delegates to the corresponding scripted constructor method in the instance namespace. Constructors contain special switch logic which allows the BeanShell to control the calling of alternate constructors (this() or super() references) at runtime.
Specially named superclass delegator methods are also generated in order to allow BeanShell to access overridden methods of the superclass (which reflection does not normally allow).
TODO: We have hooks for generating static initializer code, now used to save persistent class stubs. This must be extended to accommodate general static initializer blocks.
- Author:
- Pat Niemeyer
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static class
ClassGeneratorUtil.ConstructorArgs
A ConstructorArgs object holds evaluated arguments for a constructor call as well as the index of a possible alternate selector to invoke.
-
Field Summary
-
Fields inherited from interface bsh.org.objectweb.asm.Constants
AALOAD, AASTORE, ACC_ABSTRACT, ACC_DEPRECATED, ACC_FINAL, ACC_INTERFACE, ACC_NATIVE, ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC, ACC_STATIC, ACC_STRICT, ACC_SUPER, ACC_SYNCHRONIZED, ACC_SYNTHETIC, ACC_TRANSIENT, ACC_VOLATILE, ACONST_NULL, ALOAD, ANEWARRAY, ARETURN, ARRAYLENGTH, ASTORE, ATHROW, BALOAD, BASTORE, BIPUSH, CALOAD, CASTORE, CHECKCAST, D2F, D2I, D2L, DADD, DALOAD, DASTORE, DCMPG, DCMPL, DCONST_0, DCONST_1, DDIV, DLOAD, DMUL, DNEG, DREM, DRETURN, DSTORE, DSUB, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, F2D, F2I, F2L, FADD, FALOAD, FASTORE, FCMPG, FCMPL, FCONST_0, FCONST_1, FCONST_2, FDIV, FLOAD, FMUL, FNEG, FREM, FRETURN, FSTORE, FSUB, GETFIELD, GETSTATIC, GOTO, 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, 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, LOOKUPSWITCH, LOR, LREM, LRETURN, LSHL, LSHR, LSTORE, LSUB, LUSHR, LXOR, MONITORENTER, MONITOREXIT, MULTIANEWARRAY, NEW, NEWARRAY, NOP, POP, POP2, PUTFIELD, PUTSTATIC, RET, RETURN, SALOAD, SASTORE, SIPUSH, SWAP, T_BOOLEAN, T_BYTE, T_CHAR, T_DOUBLE, T_FLOAT, T_INT, T_LONG, T_SHORT, TABLESWITCH
-
-
Constructor Summary
Constructors Constructor Description ClassGeneratorUtil(Modifiers classModifiers, java.lang.String className, java.lang.String packageName, java.lang.Class superClass, java.lang.Class[] interfaces, Variable[] vars, DelayedEvalBshMethod[] bshmethods, boolean isInterface)
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description byte[]
generateClass(boolean generateInitCode)
Generate the class bytecode for this class.static void
generateParameterReifierCode(java.lang.String[] paramTypes, boolean isStatic, bsh.org.objectweb.asm.CodeVisitor cv)
Generates the code to reify the arguments of the given method.static void
generateReturnCode(java.lang.String returnType, bsh.org.objectweb.asm.CodeVisitor cv)
Generates the code to unreify the result of the given method.static ClassGeneratorUtil.ConstructorArgs
getConstructorArgs(java.lang.String superClassName, This classStaticThis, java.lang.Object[] consArgs, int index)
This method is called by the **generated class** during construction.static void
initInstance(java.lang.Object instance, java.lang.String className, java.lang.Object[] args)
This method is called from the **generated class** constructor to evaluate the instance initializer (instance blocks and loosely typed statements) and then the scripted constructor, in the instance namespace.static void
initStatic(java.lang.Class genClass)
The class is "cold" (detached with no live interpreter static This reference) try to start a new interpreter and source the script backing it.void
initStaticNameSpace(NameSpace classStaticNameSpace, bsh.BSHBlock instanceInitBlock)
This method provides a hook for the class generator implementation to store additional information in the class's bsh static namespace.static void
startInterpreterForClass(java.lang.Class genClass)
Attempt to load a script named for the class: e.g.
-
-
-
Constructor Detail
-
ClassGeneratorUtil
public ClassGeneratorUtil(Modifiers classModifiers, java.lang.String className, java.lang.String packageName, java.lang.Class superClass, java.lang.Class[] interfaces, Variable[] vars, DelayedEvalBshMethod[] bshmethods, boolean isInterface)
- Parameters:
packageName
- e.g. "com.foo.bar"
-
-
Method Detail
-
initStaticNameSpace
public void initStaticNameSpace(NameSpace classStaticNameSpace, bsh.BSHBlock instanceInitBlock)
This method provides a hook for the class generator implementation to store additional information in the class's bsh static namespace. Currently this is used to store an array of consructors corresponding to the constructor switch in the generated class. This method must be called to initialize the static space even if we are using a previously generated class.
-
generateClass
public byte[] generateClass(boolean generateInitCode)
Generate the class bytecode for this class.
-
generateParameterReifierCode
public static void generateParameterReifierCode(java.lang.String[] paramTypes, boolean isStatic, bsh.org.objectweb.asm.CodeVisitor cv)
Generates the code to reify the arguments of the given method. For a method "int m (int i, String s)", this code is the bytecode corresponding to the "new Object[] { new bsh.Primitive(i), s }" expression.- Parameters:
cv
- the code visitor to be used to generate the bytecode.isStatic
- the enclosing methods is static
-
generateReturnCode
public static void generateReturnCode(java.lang.String returnType, bsh.org.objectweb.asm.CodeVisitor cv)
Generates the code to unreify the result of the given method. For a method "int m (int i, String s)", this code is the bytecode corresponding to the "((Integer)...).intValue()" expression.- Parameters:
cv
- the code visitor to be used to generate the bytecode.
-
getConstructorArgs
public static ClassGeneratorUtil.ConstructorArgs getConstructorArgs(java.lang.String superClassName, This classStaticThis, java.lang.Object[] consArgs, int index)
This method is called by the **generated class** during construction. Evaluate the arguments (if any) for the constructor specified by the constructor index. Return the ConstructorArgs object which contains the actual arguments to the alternate constructor and also the index of that constructor for the constructor switch.- Parameters:
consArgs
- the arguments to the constructor. These are necessary in the evaluation of the alt constructor args. e.g. Foo(a) { super(a); }- Returns:
- the ConstructorArgs object containing a constructor selector and evaluated arguments for the alternate constructor
-
initInstance
public static void initInstance(java.lang.Object instance, java.lang.String className, java.lang.Object[] args)
This method is called from the **generated class** constructor to evaluate the instance initializer (instance blocks and loosely typed statements) and then the scripted constructor, in the instance namespace. These activities happen in the bsh script but have side effects in the generated stub class (imported instance and static variables may be initialized).
-
initStatic
public static void initStatic(java.lang.Class genClass)
The class is "cold" (detached with no live interpreter static This reference) try to start a new interpreter and source the script backing it. We pass in both the fq class name and the static This ref here just to minimize the generated code. All we really do here is a simple if condition for now.
-
startInterpreterForClass
public static void startInterpreterForClass(java.lang.Class genClass)
Attempt to load a script named for the class: e.g. Foo.class Foo.bsh. The script is expected to (at minimum) initialize the class body. That is, it should contain the scripted class definition. This method relies on the fact that the ClassGenerator generateClass() method will detect that the generated class already exists and initialize it rather than recreating it. The only interact that this method has with the process is to initially cache the correct class in the class manager for the interpreter to insure that it is found and associated with the scripted body.
-
-