package org.glassfish.pfl.dynamic.codegen.impl ;
import org.glassfish.pfl.basic.func.UnaryVoidFunction;
import java.util.BitSet ;
import java.util.List ;
import java.util.ArrayList ;
import java.util.Iterator ;
import org.glassfish.pfl.dynamic.codegen.spi.Type ;
import org.glassfish.pfl.dynamic.codegen.spi.Variable ;
import org.glassfish.pfl.dynamic.codegen.spi.ClassInfo ;
import org.glassfish.pfl.dynamic.codegen.spi.FieldInfo ;
import org.glassfish.pfl.objectweb.asm.MethodVisitor ;
import static org.glassfish.pfl.objectweb.asm.Opcodes.* ;
public final class EmitterFactory {
private EmitterFactory() {}
public interface Emitter extends UnaryVoidFunction<MethodVisitor> {
}
private static final int MAX_OPCODE = 255 ;
private static String[] opcodeNames = new String[MAX_OPCODE+1] ;
static {
for (int ctr = 0; ctr<=MAX_OPCODE; ctr++)
opcodeNames[ctr] = "ILLEGAL_" + ctr ;
opcodeNames[0] = "NOP" ;
opcodeNames[1] = "ACONST_NULL" ;
opcodeNames[2] = "ICONST_M1" ;
opcodeNames[3] = "ICONST_0" ;
opcodeNames[4] = "ICONST_1" ;
opcodeNames[5] = "ICONST_2" ;
opcodeNames[6] = "ICONST_3" ;
opcodeNames[7] = "ICONST_4" ;
opcodeNames[8] = "ICONST_5" ;
opcodeNames[9] = "LCONST_0" ;
opcodeNames[10] = "LCONST_1" ;
opcodeNames[11] = "FCONST_0" ;
opcodeNames[12] = "FCONST_1" ;
opcodeNames[13] = "FCONST_2" ;
opcodeNames[14] = "DCONST_0" ;
opcodeNames[15] = "DCONST_1" ;
opcodeNames[16] = "BIPUSH" ;
opcodeNames[17] = "SIPUSH" ;
opcodeNames[18] = "LDC" ;
opcodeNames[19] = "LDC_W" ;
opcodeNames[20] = "LDC2_W" ;
opcodeNames[21] = "ILOAD" ;
opcodeNames[22] = "LLOAD" ;
opcodeNames[23] = "FLOAD" ;
opcodeNames[24] = "DLOAD" ;
opcodeNames[25] = "ALOAD" ;
opcodeNames[26] = "ILOAD_0" ;
opcodeNames[27] = "ILOAD_1" ;
opcodeNames[28] = "ILOAD_2" ;
opcodeNames[29] = "ILOAD_3" ;
opcodeNames[30] = "LLOAD_0" ;
opcodeNames[31] = "LLOAD_1" ;
opcodeNames[32] = "LLOAD_2" ;
opcodeNames[33] = "LLOAD_3" ;
opcodeNames[34] = "FLOAD_0" ;
opcodeNames[35] = "FLOAD_1" ;
opcodeNames[36] = "FLOAD_2" ;
opcodeNames[37] = "FLOAD_3" ;
opcodeNames[38] = "DLOAD_0" ;
opcodeNames[39] = "DLOAD_1" ;
opcodeNames[40] = "DLOAD_2" ;
opcodeNames[41] = "DLOAD_3" ;
opcodeNames[42] = "ALOAD_0" ;
opcodeNames[43] = "ALOAD_1" ;
opcodeNames[44] = "ALOAD_2" ;
opcodeNames[45] = "ALOAD_3" ;
opcodeNames[46] = "IALOAD" ;
opcodeNames[47] = "LALOAD" ;
opcodeNames[48] = "FALOAD" ;
opcodeNames[49] = "DALOAD" ;
opcodeNames[50] = "AALOAD" ;
opcodeNames[51] = "BALOAD" ;
opcodeNames[52] = "CALOAD" ;
opcodeNames[53] = "SALOAD" ;
opcodeNames[54] = "ISTORE" ;
opcodeNames[55] = "LSTORE" ;
opcodeNames[56] = "FSTORE" ;
opcodeNames[57] = "DSTORE" ;
opcodeNames[58] = "ASTORE" ;
opcodeNames[59] = "ISTORE_0" ;
opcodeNames[60] = "ISTORE_1" ;
opcodeNames[61] = "ISTORE_2" ;
opcodeNames[62] = "ISTORE_3" ;
opcodeNames[63] = "LSTORE_0" ;
opcodeNames[64] = "LSTORE_1" ;
opcodeNames[65] = "LSTORE_2" ;
opcodeNames[66] = "LSTORE_3" ;
opcodeNames[67] = "FSTORE_0" ;
opcodeNames[68] = "FSTORE_1" ;
opcodeNames[69] = "FSTORE_2" ;
opcodeNames[70] = "FSTORE_3" ;
opcodeNames[71] = "DSTORE_0" ;
opcodeNames[72] = "DSTORE_1" ;
opcodeNames[73] = "DSTORE_2" ;
opcodeNames[74] = "DSTORE_3" ;
opcodeNames[75] = "ASTORE_0" ;
opcodeNames[76] = "ASTORE_1" ;
opcodeNames[77] = "ASTORE_2" ;
opcodeNames[78] = "ASTORE_3" ;
opcodeNames[79] = "IASTORE" ;
opcodeNames[80] = "LASTORE" ;
opcodeNames[81] = "FASTORE" ;
opcodeNames[82] = "DASTORE" ;
opcodeNames[83] = "AASTORE" ;
opcodeNames[84] = "BASTORE" ;
opcodeNames[85] = "CASTORE" ;
opcodeNames[86] = "SASTORE" ;
opcodeNames[87] = "POP" ;
opcodeNames[88] = "POP2" ;
opcodeNames[89] = "DUP" ;
opcodeNames[90] = "DUP_X1" ;
opcodeNames[91] = "DUP_X2" ;
opcodeNames[92] = "DUP2" ;
opcodeNames[93] = "DUP2_X1" ;
opcodeNames[94] = "DUP2_X2" ;
opcodeNames[95] = "SWAP" ;
opcodeNames[96] = "IADD" ;
opcodeNames[97] = "LADD" ;
opcodeNames[98] = "FADD" ;
opcodeNames[99] = "DADD" ;
opcodeNames[100] = "ISUB" ;
opcodeNames[101] = "LSUB" ;
opcodeNames[102] = "FSUB" ;
opcodeNames[103] = "DSUB" ;
opcodeNames[104] = "IMUL" ;
opcodeNames[105] = "LMUL" ;
opcodeNames[106] = "FMUL" ;
opcodeNames[107] = "DMUL" ;
opcodeNames[108] = "IDIV" ;
opcodeNames[109] = "LDIV" ;
opcodeNames[110] = "FDIV" ;
opcodeNames[111] = "DDIV" ;
opcodeNames[112] = "IREM" ;
opcodeNames[113] = "LREM" ;
opcodeNames[114] = "FREM" ;
opcodeNames[115] = "DREM" ;
opcodeNames[116] = "INEG" ;
opcodeNames[117] = "LNEG" ;
opcodeNames[118] = "FNEG" ;
opcodeNames[119] = "DNEG" ;
opcodeNames[120] = "ISHL" ;
opcodeNames[121] = "LSHL" ;
opcodeNames[122] = "ISHR" ;
opcodeNames[123] = "LSHR" ;
opcodeNames[124] = "IUSHR" ;
opcodeNames[125] = "LUSHR" ;
opcodeNames[126] = "IAND" ;
opcodeNames[127] = "LAND" ;
opcodeNames[128] = "IOR" ;
opcodeNames[129] = "LOR" ;
opcodeNames[130] = "IXOR" ;
opcodeNames[131] = "LXOR" ;
opcodeNames[132] = "IINC" ;
opcodeNames[133] = "I2L" ;
opcodeNames[134] = "I2F" ;
opcodeNames[135] = "I2D" ;
opcodeNames[136] = "L2I" ;
opcodeNames[137] = "L2F" ;
opcodeNames[138] = "L2D" ;
opcodeNames[139] = "F2I" ;
opcodeNames[140] = "F2L" ;
opcodeNames[141] = "F2D" ;
opcodeNames[142] = "D2I" ;
opcodeNames[143] = "D2L" ;
opcodeNames[144] = "D2F" ;
opcodeNames[145] = "I2B" ;
opcodeNames[146] = "I2C" ;
opcodeNames[147] = "I2S" ;
opcodeNames[148] = "LCMP" ;
opcodeNames[149] = "FCMPL" ;
opcodeNames[150] = "FCMPG" ;
opcodeNames[151] = "DCMPL" ;
opcodeNames[152] = "DCMPG" ;
opcodeNames[153] = "IFEQ" ;
opcodeNames[154] = "IFNE" ;
opcodeNames[155] = "IFLT" ;
opcodeNames[156] = "IFGE" ;
opcodeNames[157] = "IFGT" ;
opcodeNames[158] = "IFLE" ;
opcodeNames[159] = "IF_ICMPEQ" ;
opcodeNames[160] = "IF_ICMPNE" ;
opcodeNames[161] = "IF_ICMPLT" ;
opcodeNames[162] = "IF_ICMPGE" ;
opcodeNames[163] = "IF_ICMPGT" ;
opcodeNames[164] = "IF_ICMPLE" ;
opcodeNames[165] = "IF_ACMPEQ" ;
opcodeNames[166] = "IF_ACMPNE" ;
opcodeNames[167] = "GOTO" ;
opcodeNames[168] = "JSR" ;
opcodeNames[169] = "RET" ;
opcodeNames[170] = "TABLESWITCH" ;
opcodeNames[171] = "LOOKUPSWITCH" ;
opcodeNames[172] = "IRETURN" ;
opcodeNames[173] = "LRETURN" ;
opcodeNames[174] = "FRETURN" ;
opcodeNames[175] = "DRETURN" ;
opcodeNames[176] = "ARETURN" ;
opcodeNames[177] = "RETURN" ;
opcodeNames[178] = "GETSTATIC" ;
opcodeNames[179] = "PUTSTATIC" ;
opcodeNames[180] = "GETFIELD" ;
opcodeNames[181] = "PUTFIELD" ;
opcodeNames[182] = "INVOKEVIRTUAL" ;
opcodeNames[183] = "INVOKESPECIAL" ;
opcodeNames[184] = "INVOKESTATIC" ;
opcodeNames[185] = "INVOKEINTERFACE" ;
opcodeNames[186] = "UNUSED" ;
opcodeNames[187] = "NEW" ;
opcodeNames[188] = "NEWARRAY" ;
opcodeNames[189] = "ANEWARRAY" ;
opcodeNames[190] = "ARRAYLENGTH" ;
opcodeNames[191] = "ATHROW" ;
opcodeNames[192] = "CHECKCAST" ;
opcodeNames[193] = "INSTANCEOF" ;
opcodeNames[194] = "MONITORENTER" ;
opcodeNames[195] = "MONITOREXIT" ;
opcodeNames[196] = "WIDE" ;
opcodeNames[197] = "MULTIANEWARRAY" ;
opcodeNames[198] = "IFNULL" ;
opcodeNames[199] = "IFNONNULL" ;
opcodeNames[200] = "GOTO_W" ;
opcodeNames[201] = "JSR_W" ;
}
private static BitSet makeBitSet( int... args ) {
BitSet result = new BitSet( MAX_OPCODE + 1 ) ;
for (int value : args )
result.set( value ) ;
return result ;
}
private static BitSet visitInsnSet = makeBitSet( NOP, ACONST_NULL,
ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5,
LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1,
IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP,
IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL,
IDIV, LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG,
ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR,
I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F,
I2B, I2C, I2S,
LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, DRETURN,
ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, MONITOREXIT,
ARRAYLENGTH ) ;
private static BitSet visitIntInsnSet = makeBitSet( BIPUSH, SIPUSH,
NEWARRAY ) ;
private static BitSet visitVarInsnSet = makeBitSet(
ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, RET,
ISTORE, LSTORE, FSTORE, DSTORE, ASTORE ) ;
private static BitSet visitFieldInsnSet = makeBitSet(
GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD ) ;
private static BitSet visitMethodInsnSet = makeBitSet(
INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE ) ;
private static BitSet visitTypeInsnSet = makeBitSet(
NEW, ANEWARRAY, CHECKCAST, INSTANCEOF ) ;
private static BitSet visitJumpInsnSet = makeBitSet(
IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE,
IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL, IFNONNULL ) ;
private static BitSet specialOpcodeSet = makeBitSet( IINC, LDC,
TABLESWITCH, LOOKUPSWITCH, MULTIANEWARRAY ) ;
private static BitSet validOpcodeSet = makeBitSet() ;
static {
validOpcodeSet.or( visitInsnSet ) ;
validOpcodeSet.or( visitIntInsnSet ) ;
validOpcodeSet.or( visitVarInsnSet ) ;
validOpcodeSet.or( visitFieldInsnSet ) ;
validOpcodeSet.or( visitMethodInsnSet ) ;
validOpcodeSet.or( visitTypeInsnSet ) ;
validOpcodeSet.or( visitJumpInsnSet ) ;
validOpcodeSet.or( specialOpcodeSet ) ;
}
private static void check( BitSet validOps, int op ) {
if (!validOpcodeSet.get( op ))
throw new IllegalArgumentException(
op + " is not a valid Bytecode" ) ;
if (!validOps.get( op ))
throw new IllegalArgumentException(
op + " is not a valid Bytecode for this emitter" ) ;
}
public static class NullEmitter implements Emitter {
public NullEmitter() { }
public void evaluate( MethodVisitor mv ) {
}
@Override
public String toString() {
return "NullEmitter[]" ;
}
@Override
public int hashCode() {
return 0 ;
}
@Override
public boolean equals( Object obj ) {
if (obj == this)
return true ;
if (!(obj instanceof NullEmitter))
return false ;
return true ;
}
}
public static class CompoundEmitter implements Emitter {
private List<Emitter> emitters;
public CompoundEmitter( Emitter... args ) {
emitters = new ArrayList<Emitter>() ;
for (Emitter e : args)
emitters.add( e ) ;
}
public void evaluate( MethodVisitor mv ) {
for (Emitter e : emitters)
e.evaluate( mv ) ;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder() ;
sb.append( "CompoundEmitter[" ) ;
boolean first = true ;
for (Emitter e : emitters) {
if (first)
first = false ;
else
sb.append( ", " ) ;
sb.append( e.toString() ) ;
}
sb.append( "]" ) ;
return sb.toString() ;
}
@Override
public int hashCode() {
int hash = 0 ;
for (Emitter e : emitters)
hash ^= e.hashCode() ;
return hash ;
}
@Override
public boolean equals( Object obj ) {
if (obj == this)
return true ;
if (!(obj instanceof CompoundEmitter))
return false ;
CompoundEmitter other = CompoundEmitter.class.cast( obj ) ;
Iterator<Emitter> it1 = emitters.iterator() ;
Iterator<Emitter> it2 = other.emitters.iterator() ;
while (it1.hasNext() && it2.hasNext()) {
Emitter e1 = it1.next() ;
Emitter e2 = it2.next() ;
if (!e1.equals( e2 ))
return false ;
}
return it1.hasNext() == it2.hasNext() ;
}
}
public static class SimpleEmitter implements Emitter {
private int opcode ;
public SimpleEmitter( int opcode ) {
check( visitInsnSet, opcode ) ;
this.opcode = opcode ;
}
public void evaluate( MethodVisitor mv ) {
mv.visitInsn( opcode ) ;
}
@Override
public String toString() {
return "SimpleEmitter[" + opcodeNames[opcode] + "]" ;
}
@Override
public int hashCode() {
return opcode ;
}
public boolean equals( Object obj ) {
if (obj == this)
return true ;
if (!(obj instanceof SimpleEmitter))
return false ;
SimpleEmitter other = SimpleEmitter.class.cast( obj ) ;
return other.opcode == opcode ;
}
}
private static class IntOperandEmitter implements Emitter {
private static BitSet validOps = new BitSet() ;
static {
validOps.or( visitIntInsnSet ) ;
validOps.or( visitVarInsnSet ) ;
}
private int opcode ;
private int arg ;
public IntOperandEmitter( int opcode, int arg ) {
check( validOps, opcode ) ;
this.opcode = opcode ;
this.arg = arg ;
}
public void evaluate( MethodVisitor mv ) {
if (visitIntInsnSet.get( opcode )) {
mv.visitIntInsn( opcode, arg ) ;
} else {
assert visitVarInsnSet.get( opcode ) ;
mv.visitVarInsn( opcode, arg ) ;
}
}
public String toString() {
return "IntOperandEmitter[" + opcodeNames[opcode] + " "
+ arg + "]" ;
}
public int hashCode() {
return opcode * 91 + arg ;
}
public boolean equals( Object obj ) {
if (obj == this)
return true ;
if (!(obj instanceof IntOperandEmitter))
return false ;
IntOperandEmitter other =
IntOperandEmitter.class.cast( obj ) ;
return other.opcode == opcode && other.arg == arg ;
}
}
private static class FieldInsnEmitter implements Emitter {
private int opcode ;
private String owner ;
private String name ;
private String desc ;
public FieldInsnEmitter( int opcode, String owner, String name,
String desc ) {
check( visitFieldInsnSet, opcode ) ;
this.opcode = opcode ;
this.owner = owner ;
this.name = name ;
this.desc = desc ;
}
public void evaluate( MethodVisitor mv ) {
mv.visitFieldInsn( opcode, owner, name, desc ) ;
}
public String toString() {
return "FieldInsnEmitter[" + opcodeNames[opcode]
+ " \"" + owner + "\""
+ " \"" + name + "\""
+ " \"" + desc + "\""
+ "]" ;
}
public int hashCode() {
return opcode * 91 ^ owner.hashCode()
^ name.hashCode() ^ desc.hashCode() ;
}
public boolean equals( Object obj ) {
if (obj == this)
return true ;
if (!(obj instanceof FieldInsnEmitter))
return false ;
FieldInsnEmitter other = FieldInsnEmitter.class.cast( obj ) ;
return other.opcode == opcode &&
other.owner.equals( owner ) &&
other.name.equals( name ) &&
other.desc.equals( desc ) ;
}
}
private static int getVarInsnOpcode( Type type, boolean isStore ) {
if (isStore) {
if (!type.isPrimitive()) {
return ASTORE ;
} else if (type == Type._float()) {
return FSTORE ;
} else if (type == Type._double()) {
return DSTORE ;
} else if (type == Type._long()) {
return LSTORE ;
} else {
return ISTORE ;
}
} else {
if (!type.isPrimitive()) {
return ALOAD ;
} else if (type == Type._float()) {
return FLOAD ;
} else if (type == Type._double()) {
return DLOAD ;
} else if (type == Type._long()) {
return LLOAD ;
} else {
return ILOAD ;
}
}
}
private static Emitter makeFieldInsnEmitter( boolean isStore, boolean isStatic,
Type targetType, String name, Type varType ) {
String owner = ASMUtil.bcName( targetType ) ;
String descriptor = varType.signature() ;
int insn = isStore ?
(isStatic ? PUTSTATIC : PUTFIELD) :
(isStatic ? GETSTATIC : GETFIELD) ;
return new FieldInsnEmitter( insn, owner, name, descriptor ) ;
}
public static Emitter makeEmitter( Variable var, boolean isStore ) {
VariableInternal ivar = (VariableInternal)var ;
Integer slot = ASMUtil.stackFrameSlot.get( ivar ) ;
assert slot != null ;
return new IntOperandEmitter( getVarInsnOpcode( ivar.type(), isStore ),
slot ) ;
}
public static Emitter makeEmitter(
ExpressionFactory.NonStaticFieldAccessExpression expr,
boolean isStore ) {
Type targetType = ((ExpressionInternal)expr.target()).type() ;
ClassInfo cinfo = targetType.classInfo() ;
FieldInfo fld = cinfo.fieldInfo().get( expr.fieldName() ) ;
if (fld == null) {
throw new IllegalArgumentException( expr.fieldName()
+ " is not a valid field in class " + targetType.name() ) ;
}
return makeFieldInsnEmitter( isStore, false, targetType,
expr.fieldName(), fld.type() ) ;
}
public static Emitter makeEmitter(
ExpressionFactory.StaticFieldAccessExpression expr,
boolean isStore ) {
Type targetType = expr.target() ;
ClassInfo cinfo = targetType.classInfo() ;
FieldInfo fld = cinfo.fieldInfo().get( expr.fieldName() ) ;
if (fld == null)
throw new IllegalArgumentException( expr.fieldName() +
" is not a valid field in class " + targetType.name() ) ;
return makeFieldInsnEmitter( isStore, true, targetType,
expr.fieldName(), fld.type() ) ;
}
private static final Emitter arrayStore = new SimpleEmitter( AASTORE ) ;
private static final Emitter arrayLoad = new SimpleEmitter( AALOAD ) ;
public static Emitter makeEmitter(
ExpressionFactory.ArrayIndexExpression expr,
boolean isStore ) {
if (isStore) {
return arrayStore ;
} else {
return arrayLoad ;
}
}
private static final Emitter arrayLength = new SimpleEmitter( ARRAYLENGTH ) ;
public static Emitter makeEmitter( ExpressionFactory.ArrayLengthExpression expr ) {
return arrayLength ;
}
}